summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2014-05-17 18:21:01 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2014-05-17 18:21:12 +0200
commit0776cdbf335240a1b2a1eec89cabf912d40a01b5 (patch)
tree93a04ea02bc64bc327d3aebde20c252225b21332 /target
parent11616aa25b1e2c9b131c408ceb219ae059f093dd (diff)
bump lts kernels, add yaffs2 kernel patch
Diffstat (limited to 'target')
-rw-r--r--target/linux/config/Config.in.flash32
-rw-r--r--target/linux/config/Config.in.fs12
-rw-r--r--target/linux/patches/3.10.40/bsd-compatibility.patch (renamed from target/linux/patches/3.10.37/bsd-compatibility.patch)0
-rw-r--r--target/linux/patches/3.10.40/startup.patch (renamed from target/linux/patches/3.10.37/startup.patch)0
-rw-r--r--target/linux/patches/3.10.40/yaffs2.patch16547
-rw-r--r--target/linux/patches/3.11.10/arm-spitz.patch27
-rw-r--r--target/linux/patches/3.11.10/raspberry.patch97980
-rw-r--r--target/linux/patches/3.11.10/startup.patch34
-rw-r--r--target/linux/patches/3.12.18/bsd-compatibility.patch2538
-rw-r--r--target/linux/patches/3.12.18/defaults.patch46
-rw-r--r--target/linux/patches/3.12.18/disable-netfilter.patch160
-rw-r--r--target/linux/patches/3.12.18/export-symbol-for-exmap.patch11
-rw-r--r--target/linux/patches/3.12.18/microblaze-ethernet.patch11
-rw-r--r--target/linux/patches/3.12.18/microblaze-setup.patch12
-rw-r--r--target/linux/patches/3.12.18/mips-lzo-fix.patch12
-rw-r--r--target/linux/patches/3.12.18/mtd-rootfs.patch26
-rw-r--r--target/linux/patches/3.12.18/ppc64-missing-zlib.patch11
-rw-r--r--target/linux/patches/3.12.18/usb-defaults-off.patch20
-rw-r--r--target/linux/patches/3.12.18/vga-cons-default-off.patch12
-rw-r--r--target/linux/patches/3.12.20/bsd-compatibility.patch (renamed from target/linux/patches/3.11.10/bsd-compatibility.patch)0
-rw-r--r--target/linux/patches/3.12.20/defaults.patch (renamed from target/linux/patches/3.11.10/defaults.patch)0
-rw-r--r--target/linux/patches/3.12.20/disable-netfilter.patch (renamed from target/linux/patches/3.11.10/disable-netfilter.patch)0
-rw-r--r--target/linux/patches/3.12.20/export-symbol-for-exmap.patch (renamed from target/linux/patches/3.11.10/export-symbol-for-exmap.patch)0
-rw-r--r--target/linux/patches/3.12.20/gemalto.patch (renamed from target/linux/patches/3.11.10/gemalto.patch)0
-rw-r--r--target/linux/patches/3.12.20/lemote-rfkill.patch (renamed from target/linux/patches/3.11.10/lemote-rfkill.patch)0
-rw-r--r--target/linux/patches/3.12.20/microblaze-ethernet.patch (renamed from target/linux/patches/3.11.10/microblaze-ethernet.patch)0
-rw-r--r--target/linux/patches/3.12.20/microblaze-setup.patch (renamed from target/linux/patches/3.11.10/microblaze-setup.patch)0
-rw-r--r--target/linux/patches/3.12.20/mips-lzo-fix.patch (renamed from target/linux/patches/3.11.10/mips-lzo-fix.patch)0
-rw-r--r--target/linux/patches/3.12.20/mtd-rootfs.patch (renamed from target/linux/patches/3.11.10/mtd-rootfs.patch)0
-rw-r--r--target/linux/patches/3.12.20/non-static.patch (renamed from target/linux/patches/3.11.10/non-static.patch)0
-rw-r--r--target/linux/patches/3.12.20/ppc64-missing-zlib.patch (renamed from target/linux/patches/3.11.10/ppc64-missing-zlib.patch)0
-rw-r--r--target/linux/patches/3.12.20/startup.patch (renamed from target/linux/patches/3.12.18/startup.patch)0
-rw-r--r--target/linux/patches/3.12.20/usb-defaults-off.patch (renamed from target/linux/patches/3.11.10/usb-defaults-off.patch)0
-rw-r--r--target/linux/patches/3.12.20/uuid.patch (renamed from target/linux/patches/3.11.10/uuid.patch)0
-rw-r--r--target/linux/patches/3.12.20/vga-cons-default-off.patch (renamed from target/linux/patches/3.11.10/vga-cons-default-off.patch)0
-rw-r--r--target/linux/patches/3.12.20/wlan-cf.patch (renamed from target/linux/patches/3.11.10/wlan-cf.patch)0
-rw-r--r--target/linux/patches/3.12.20/xargs.patch (renamed from target/linux/patches/3.12.18/xargs.patch)0
-rw-r--r--target/linux/patches/3.12.20/yaffs2.patch16547
-rw-r--r--target/linux/patches/3.12.20/zlib-inflate.patch (renamed from target/linux/patches/3.11.10/zlib-inflate.patch)0
-rw-r--r--target/linux/patches/3.13.11/yaffs2.patch16547
-rw-r--r--target/linux/patches/3.4.87/gemalto.patch11
-rw-r--r--target/linux/patches/3.4.87/lemote-rfkill.patch21
-rw-r--r--target/linux/patches/3.4.87/non-static.patch33
-rw-r--r--target/linux/patches/3.4.87/uuid.patch263
-rw-r--r--target/linux/patches/3.4.87/wlan-cf.patch11
-rw-r--r--target/linux/patches/3.4.87/zlib-inflate.patch12
-rw-r--r--target/linux/patches/3.4.90/bsd-compatibility.patch (renamed from target/linux/patches/3.4.87/bsd-compatibility.patch)0
-rw-r--r--target/linux/patches/3.4.90/defaults.patch (renamed from target/linux/patches/3.4.87/defaults.patch)0
-rw-r--r--target/linux/patches/3.4.90/gemalto.patch (renamed from target/linux/patches/3.12.18/gemalto.patch)0
-rw-r--r--target/linux/patches/3.4.90/lemote-rfkill.patch (renamed from target/linux/patches/3.12.18/lemote-rfkill.patch)0
-rw-r--r--target/linux/patches/3.4.90/mips-error.patch (renamed from target/linux/patches/3.4.87/mips-error.patch)0
-rw-r--r--target/linux/patches/3.4.90/module-alloc-size-check.patch (renamed from target/linux/patches/3.4.87/module-alloc-size-check.patch)0
-rw-r--r--target/linux/patches/3.4.90/non-static.patch (renamed from target/linux/patches/3.12.18/non-static.patch)0
-rw-r--r--target/linux/patches/3.4.90/sparc-include.patch (renamed from target/linux/patches/3.4.87/sparc-include.patch)0
-rw-r--r--target/linux/patches/3.4.90/startup.patch (renamed from target/linux/patches/3.4.87/startup.patch)0
-rw-r--r--target/linux/patches/3.4.90/usb-defaults-off.patch (renamed from target/linux/patches/3.4.87/usb-defaults-off.patch)0
-rw-r--r--target/linux/patches/3.4.90/uuid.patch (renamed from target/linux/patches/3.12.18/uuid.patch)0
-rw-r--r--target/linux/patches/3.4.90/vga-cons-default-off.patch (renamed from target/linux/patches/3.4.87/vga-cons-default-off.patch)0
-rw-r--r--target/linux/patches/3.4.90/wlan-cf.patch (renamed from target/linux/patches/3.12.18/wlan-cf.patch)0
-rw-r--r--target/linux/patches/3.4.90/yaffs2.patch16550
-rw-r--r--target/linux/patches/3.4.90/zlib-inflate.patch (renamed from target/linux/patches/3.12.18/zlib-inflate.patch)0
61 files changed, 66202 insertions, 101284 deletions
diff --git a/target/linux/config/Config.in.flash b/target/linux/config/Config.in.flash
index d35f1c866..47d6f6c35 100644
--- a/target/linux/config/Config.in.flash
+++ b/target/linux/config/Config.in.flash
@@ -110,38 +110,6 @@ config ADK_KERNEL_MTD_AR2315
default y if ADK_TARGET_SYSTEM_FON_FON2100
default n
-config ADK_TARGET_NAND
- boolean
- select ADK_KERNEL_MISC_FILESYSTEMS
- select ADK_KERNEL_YAFFS_FS
- select ADK_KERNEL_YAFFS_YAFFS2
- select ADK_KERNEL_YAFFS_AUTO_YAFFS2
- select ADK_KERNEL_MTD
- select ADK_KERNEL_MTD_PARTITIONS
- select ADK_KERNEL_MTD_NAND
- select ADK_KERNEL_MTD_NAND_PLATFORM
- select ADK_KERNEL_MTD_CHAR
- select ADK_KERNEL_MTD_BLKDEVS
- select ADK_KERNEL_MTD_BLOCK
- default y if ADK_TARGET_WITH_NAND
- default n
-
-config ADK_TARGET_MTD
- boolean
- select ADK_KERNEL_MISC_FILESYSTEMS
- select ADK_KERNEL_JFFS2_FS
- select ADK_KERNEL_MTD
- select ADK_KERNEL_MTD_PARTITIONS
- select ADK_KERNEL_MTD_CHAR
- select ADK_KERNEL_MTD_BLKDEVS
- select ADK_KERNEL_MTD_BLOCK
- select ADK_KERNEL_MTD_ROOTFS_ROOT_DEV
- select ADK_KERNEL_MTD_CFI
- select ADK_KERNEL_MTD_GEN_PROBE
- select ADK_KERNEL_MTD_PHYSMAP
- default y if ADK_TARGET_WITH_MTD
- default n
-
config ADK_TARGET_MTD_SIZE
int
default "16777216" if ADK_TARGET_QEMU_MICROBLAZE_MODEL_S3ADSP1800
diff --git a/target/linux/config/Config.in.fs b/target/linux/config/Config.in.fs
index 5efed48fb..353942ba8 100644
--- a/target/linux/config/Config.in.fs
+++ b/target/linux/config/Config.in.fs
@@ -223,11 +223,17 @@ config ADK_KERNEL_UDF_FS
Please read <file:Documentation/filesystems/udf.txt>.
config ADK_KERNEL_JFFS2_FS
- tristate
prompt "JFFS2 filesystem"
+ tristate
select ADK_KERNEL_MISC_FILESYSTEMS
+ select ADK_KERNEL_MTD
+ select ADK_KERNEL_MTD_BLOCK
select ADK_KERNEL_JFFS2_COMPRESSION_OPTIONS
select ADK_KERNEL_JFFS2_ZLIB
+ depends on ADK_TARGET_WITH_MTD
+ default n
+ help
+ JFFS2 flash filesystem
config ADK_KERNEL_SQUASHFS
prompt "SquashFS filesystem"
@@ -235,6 +241,8 @@ config ADK_KERNEL_SQUASHFS
select ADK_KERNEL_MISC_FILESYSTEMS
select ADK_KERNEL_SQUASHFS_XZ
default n
+ help
+ Squashfs compressed read-only filesystem
config ADK_KERNEL_YAFFS_FS
prompt "YAFFS2 filesystem"
@@ -245,6 +253,8 @@ config ADK_KERNEL_YAFFS_FS
select ADK_KERNEL_YAFFS_YAFFS1
select ADK_KERNEL_YAFFS_YAFFS2
select ADK_KERNEL_YAFFS_AUTO_YAFFS2
+ depends on ADK_TARGET_WITH_NAND
+ default n
help
YAFFS2 filesystem for NAND devices
diff --git a/target/linux/patches/3.10.37/bsd-compatibility.patch b/target/linux/patches/3.10.40/bsd-compatibility.patch
index b954b658f..b954b658f 100644
--- a/target/linux/patches/3.10.37/bsd-compatibility.patch
+++ b/target/linux/patches/3.10.40/bsd-compatibility.patch
diff --git a/target/linux/patches/3.10.37/startup.patch b/target/linux/patches/3.10.40/startup.patch
index 3ebc5db1e..3ebc5db1e 100644
--- a/target/linux/patches/3.10.37/startup.patch
+++ b/target/linux/patches/3.10.40/startup.patch
diff --git a/target/linux/patches/3.10.40/yaffs2.patch b/target/linux/patches/3.10.40/yaffs2.patch
new file mode 100644
index 000000000..172629530
--- /dev/null
+++ b/target/linux/patches/3.10.40/yaffs2.patch
@@ -0,0 +1,16547 @@
+diff -Nur linux-3.10.40.orig/fs/Kconfig linux-3.10.40/fs/Kconfig
+--- linux-3.10.40.orig/fs/Kconfig 2014-05-13 14:00:04.000000000 +0200
++++ linux-3.10.40/fs/Kconfig 2014-05-17 12:48:10.000000000 +0200
+@@ -193,6 +193,7 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Nur linux-3.10.40.orig/fs/Makefile linux-3.10.40/fs/Makefile
+--- linux-3.10.40.orig/fs/Makefile 2014-05-13 14:00:04.000000000 +0200
++++ linux-3.10.40/fs/Makefile 2014-05-17 12:48:10.000000000 +0200
+@@ -126,3 +126,4 @@
+ obj-$(CONFIG_CEPH_FS) += ceph/
+ obj-$(CONFIG_PSTORE) += pstore/
+ obj-$(CONFIG_EFIVAR_FS) += efivarfs/
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
+diff -Nur linux-3.10.40.orig/fs/yaffs2/Kconfig linux-3.10.40/fs/yaffs2/Kconfig
+--- linux-3.10.40.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/Kconfig 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,171 @@
++#
++# yaffs file system configurations
++#
++
++config YAFFS_FS
++ tristate "yaffs2 file system support"
++ default n
++ depends on MTD_BLOCK
++ select YAFFS_YAFFS1
++ select YAFFS_YAFFS2
++ help
++ yaffs2, or Yet Another Flash File System, is a file 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
++ in yaffs_mtdif1.c.
++
++ 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_TAGS_ECC
++ bool "Disable yaffs from doing ECC on tags by default"
++ depends on YAFFS_FS && YAFFS_YAFFS2
++ default n
++ help
++ This defaults yaffs to using its own ECC calculations on tags instead of
++ just relying on the MTD.
++ This behavior can also be overridden with tags_ecc_on and
++ tags_ecc_off mount options.
++
++ 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_EMPTY_LOST_AND_FOUND
++ bool "Empty lost and found on boot"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is enabled then the contents of lost and found is
++ automatically dumped at mount.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++ bool "Disable yaffs2 block refreshing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then block refreshing is disabled.
++ Block refreshing infrequently refreshes the oldest block in
++ a yaffs2 file system. This mechanism helps to refresh flash to
++ mitigate against data loss. This is particularly useful for MLC.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++ bool "Disable yaffs2 background processing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then background processing is disabled.
++ Background processing makes many foreground activities faster.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BAD_BLOCK_MARKING
++ bool "Disable yaffs2 bad block marking"
++ depends on YAFFS_FS
++ default n
++ help
++ Useful during early flash bring up to prevent problems causing
++ lots of bad block marking.
++
++ If unsure, say N.
++
++config YAFFS_XATTR
++ bool "Enable yaffs2 xattr support"
++ depends on YAFFS_FS
++ default y
++ help
++ If this is set then yaffs2 will provide xattr support.
++ If unsure, say Y.
+diff -Nur linux-3.10.40.orig/fs/yaffs2/Makefile linux-3.10.40/fs/yaffs2/Makefile
+--- linux-3.10.40.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/Makefile 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,18 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
++yaffs-y += yaffs_mtdif.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_summary.o
++yaffs-y += yaffs_verify.o
++
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_allocator.c linux-3.10.40/fs/yaffs2/yaffs_allocator.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_allocator.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,357 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++/*
++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
++ * of approx 100 objects that are themn allocated singly.
++ * This is basically a simplified slab allocator.
++ *
++ * We don't use the Linux slab allocator because slab does not allow
++ * us to dump all the objects in one hit when we do a umount and tear
++ * down all the tnodes and objects. slab requires that we first free
++ * the individual objects.
++ *
++ * Once yaffs has been mainlined I shall try to motivate for a change
++ * to slab to provide the extra features we need here.
++ */
++
++struct yaffs_tnode_list {
++ struct yaffs_tnode_list *next;
++ struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++ struct yaffs_obj_list *next;
++ struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++ int n_tnodes_created;
++ struct yaffs_tnode *free_tnodes;
++ int n_free_tnodes;
++ struct yaffs_tnode_list *alloc_tnode_list;
++
++ int n_obj_created;
++ struct list_head free_objs;
++ int n_free_objects;
++
++ struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->alloc_tnode_list) {
++ tmp = allocator->alloc_tnode_list->next;
++
++ kfree(allocator->alloc_tnode_list->tnodes);
++ kfree(allocator->alloc_tnode_list);
++ allocator->alloc_tnode_list = tmp;
++ }
++
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->alloc_tnode_list = NULL;
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ int i;
++ struct yaffs_tnode *new_tnodes;
++ u8 *mem;
++ struct yaffs_tnode *curr;
++ struct yaffs_tnode *next;
++ struct yaffs_tnode_list *tnl;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_tnodes < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
++ mem = (u8 *) new_tnodes;
++
++ if (!new_tnodes) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: Could not allocate Tnodes");
++ return YAFFS_FAIL;
++ }
++
++ /* New hookup for wide tnodes */
++ for (i = 0; i < n_tnodes - 1; i++) {
++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++ curr->internal[0] = next;
++ }
++
++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++ curr->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++ allocator->n_free_tnodes += n_tnodes;
++ allocator->n_tnodes_created += n_tnodes;
++
++ /* Now add this bunch of tnodes to a list for freeing up.
++ * NB If we can't add this to the management list it isn't fatal
++ * but it just means we can't free this bunch of tnodes later.
++ */
++ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
++ if (!tnl) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Could not add tnodes to management list");
++ return YAFFS_FAIL;
++ } else {
++ tnl->tnodes = new_tnodes;
++ tnl->next = allocator->alloc_tnode_list;
++ allocator->alloc_tnode_list = tnl;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
++
++ return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode *tn = NULL;
++
++ if (!allocator) {
++ BUG();
++ return NULL;
++ }
++
++ /* If there are none left make more */
++ if (!allocator->free_tnodes)
++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++ if (allocator->free_tnodes) {
++ tn = allocator->free_tnodes;
++ allocator->free_tnodes = allocator->free_tnodes->internal[0];
++ allocator->n_free_tnodes--;
++ }
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ if (tn) {
++ tn->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = tn;
++ allocator->n_free_tnodes++;
++ }
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++/*--------------- yaffs_obj alloaction ------------------------
++ *
++ * Free yaffs_objs are stored in a list using obj->siblings.
++ * The blocks of allocated objects are stored in a linked list.
++ */
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->allocated_obj_list = NULL;
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ struct yaffs_obj_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->allocated_obj_list) {
++ tmp = allocator->allocated_obj_list->next;
++ kfree(allocator->allocated_obj_list->objects);
++ kfree(allocator->allocated_obj_list);
++ allocator->allocated_obj_list = tmp;
++ }
++
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++ allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ int i;
++ struct yaffs_obj *new_objs;
++ struct yaffs_obj_list *list;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_obj < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
++ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
++
++ if (!new_objs || !list) {
++ kfree(new_objs);
++ new_objs = NULL;
++ kfree(list);
++ list = NULL;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Could not allocate more objects");
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++ for (i = 0; i < n_obj; i++)
++ list_add(&new_objs[i].siblings, &allocator->free_objs);
++
++ allocator->n_free_objects += n_obj;
++ allocator->n_obj_created += n_obj;
++
++ /* Now add this bunch of Objects to a list for freeing up. */
++
++ list->objects = new_objs;
++ list->next = allocator->allocated_obj_list;
++ allocator->allocated_obj_list = list;
++
++ return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = NULL;
++ struct list_head *lh;
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return obj;
++ }
++
++ /* If there are none left make more */
++ if (list_empty(&allocator->free_objs))
++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++ if (!list_empty(&allocator->free_objs)) {
++ lh = allocator->free_objs.next;
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ list_del_init(lh);
++ allocator->n_free_objects--;
++ }
++
++ return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ /* Link into the free list. */
++ list_add(&obj->siblings, &allocator->free_objs);
++ allocator->n_free_objects++;
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++
++ if (!dev->allocator) {
++ BUG();
++ return;
++ }
++
++ yaffs_deinit_raw_tnodes(dev);
++ yaffs_deinit_raw_objs(dev);
++ kfree(dev->allocator);
++ dev->allocator = NULL;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator;
++
++ if (dev->allocator) {
++ BUG();
++ return;
++ }
++
++ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
++ if (allocator) {
++ dev->allocator = allocator;
++ yaffs_init_raw_tnodes(dev);
++ yaffs_init_raw_objs(dev);
++ }
++}
++
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_allocator.h linux-3.10.40/fs/yaffs2/yaffs_allocator.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_allocator.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_attribs.c linux-3.10.40/fs/yaffs2/yaffs_attribs.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_attribs.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return from_kuid(&init_user_ns, iattr->ia_uid);
++}
++
++static inline gid_t ia_gid_read(const struct iattr *iattr)
++{
++ return from_kgid(&init_user_ns, iattr->ia_gid);
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = make_kuid(&init_user_ns, uid);
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = make_kgid(&init_user_ns, gid);
++}
++#else
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return iattr->ia_uid;
++}
++
++static inline gid_t ia_gid_read(const struct iattr *inode)
++{
++ return iattr->ia_gid;
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = uid;
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = gid;
++}
++#endif
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++ obj->yst_uid = oh->yst_uid;
++ obj->yst_gid = oh->yst_gid;
++ obj->yst_atime = oh->yst_atime;
++ obj->yst_mtime = oh->yst_mtime;
++ obj->yst_ctime = oh->yst_ctime;
++ obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++ oh->yst_uid = obj->yst_uid;
++ oh->yst_gid = obj->yst_gid;
++ oh->yst_atime = obj->yst_atime;
++ oh->yst_mtime = obj->yst_mtime;
++ oh->yst_ctime = obj->yst_ctime;
++ oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++ obj->yst_mtime = Y_CURRENT_TIME;
++ if (do_a)
++ obj->yst_atime = obj->yst_mtime;
++ if (do_c)
++ obj->yst_ctime = obj->yst_mtime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++ yaffs_load_current_time(obj, 1, 1);
++ obj->yst_rdev = rdev;
++ obj->yst_uid = uid;
++ obj->yst_gid = gid;
++}
++
++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++ YCHAR *alias = NULL;
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return obj->variant.file_variant.file_size;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = obj->variant.symlink_variant.alias;
++ if (!alias)
++ return 0;
++ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++ default:
++ return 0;
++ }
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = attr->ia_valid;
++
++ if (valid & ATTR_MODE)
++ obj->yst_mode = attr->ia_mode;
++ if (valid & ATTR_UID)
++ obj->yst_uid = ia_uid_read(attr);
++ if (valid & ATTR_GID)
++ obj->yst_gid = ia_gid_read(attr);
++
++ if (valid & ATTR_ATIME)
++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++ if (valid & ATTR_CTIME)
++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++ if (valid & ATTR_MTIME)
++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++ if (valid & ATTR_SIZE)
++ yaffs_resize_file(obj, attr->ia_size);
++
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = 0;
++
++ attr->ia_mode = obj->yst_mode;
++ valid |= ATTR_MODE;
++ ia_uid_write(attr, obj->yst_uid);
++ valid |= ATTR_UID;
++ ia_gid_write(attr, obj->yst_gid);
++ valid |= ATTR_GID;
++
++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++ valid |= ATTR_ATIME;
++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++ valid |= ATTR_CTIME;
++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++ valid |= ATTR_MTIME;
++
++ attr->ia_size = yaffs_get_file_size(obj);
++ valid |= ATTR_SIZE;
++
++ attr->ia_valid = valid;
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_attribs.h linux-3.10.40/fs/yaffs2/yaffs_attribs.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_attribs.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_bitmap.c linux-3.10.40/fs/yaffs2/yaffs_bitmap.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_bitmap.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "BlockBits block %d is not valid",
++ blk);
++ BUG();
++ }
++ return dev->chunk_bits +
++ (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++ chunk < 0 || chunk >= dev->param.chunks_per_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Chunk Id (%d:%d) invalid",
++ blk, chunk);
++ BUG();
++ }
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++) {
++ if (*blk_bits)
++ return 1;
++ blk_bits++;
++ }
++ return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++ int n = 0;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
++ n += hweight8(*blk_bits);
++
++ return n;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_bitmap.h linux-3.10.40/fs/yaffs2/yaffs_bitmap.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_bitmap.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.10.40/fs/yaffs2/yaffs_checkptrw.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_checkptrw.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,474 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++struct yaffs_checkpt_chunk_hdr {
++ int version;
++ int seq;
++ u32 sum;
++ u32 xor;
++} ;
++
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++static int apply_block_offset(struct yaffs_dev *dev, int block)
++{
++ return block - dev->block_offset;
++}
++
++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ hdr.version = YAFFS_CHECKPOINT_VERSION;
++ hdr.seq = dev->checkpt_page_seq;
++ hdr.sum = dev->checkpt_sum;
++ hdr.xor = dev->checkpt_xor;
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
++}
++
++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ return hdr.version == YAFFS_CHECKPOINT_VERSION &&
++ hdr.seq == dev->checkpt_page_seq &&
++ hdr.sum == dev->checkpt_sum &&
++ hdr.xor == dev->checkpt_xor;
++}
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpt blocks_avail = %d", blocks_avail);
++
++ return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (!dev->drv.drv_erase_fn)
++ return 0;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checking blocks %d to %d",
++ dev->internal_start_block, dev->internal_end_block);
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ int offset_i = apply_block_offset(dev, i);
++ int result;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "erasing checkpt block %d", i);
++
++ dev->n_erasures++;
++
++ result = dev->drv.drv_erase_fn(dev, offset_i);
++ if(result) {
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ dev->n_free_chunks +=
++ dev->param.chunks_per_block;
++ } else {
++ dev->drv.drv_mark_bad_fn(dev, offset_i);
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ }
++ }
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++ int i;
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block: erased %d reserved %d avail %d next %d ",
++ dev->n_erased_blocks, dev->param.n_reserved_blocks,
++ blocks_avail, dev->checkpt_next_block);
++
++ if (dev->checkpt_next_block >= 0 &&
++ dev->checkpt_next_block <= dev->internal_end_block &&
++ blocks_avail > 0) {
++
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev, i);
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ dev->checkpt_next_block = i + 1;
++ dev->checkpt_cur_block = i;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block %d", i);
++ return;
++ }
++ }
++ }
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_ext_tags tags;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: start: blocks %d next %d",
++ dev->blocks_in_checkpt, dev->checkpt_next_block);
++
++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ int chunk = i * dev->param.chunks_per_block;
++ enum yaffs_block_state state;
++ u32 seq;
++
++ dev->tagger.read_chunk_tags_fn(dev,
++ apply_chunk_offset(dev, chunk),
++ NULL, &tags);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
++ i, (int) state,
++ tags.obj_id, tags.seq_number,
++ tags.ecc_result);
++
++ if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ continue;
++
++ dev->tagger.query_block_fn(dev,
++ apply_block_offset(dev, i),
++ &state, &seq);
++ if (state == YAFFS_BLOCK_STATE_DEAD)
++ continue;
++
++ /* Right kind of block */
++ dev->checkpt_next_block = tags.obj_id;
++ dev->checkpt_cur_block = i;
++ dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
++ dev->blocks_in_checkpt++;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "found checkpt block %d", i);
++ return;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++ int i;
++
++ dev->checkpt_open_write = writing;
++
++ /* Got the functions we need? */
++ if (!dev->tagger.write_chunk_tags_fn ||
++ !dev->tagger.read_chunk_tags_fn ||
++ !dev->drv.drv_erase_fn ||
++ !dev->drv.drv_mark_bad_fn)
++ return 0;
++
++ if (writing && !yaffs2_checkpt_space_ok(dev))
++ return 0;
++
++ if (!dev->checkpt_buffer)
++ dev->checkpt_buffer =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ dev->checkpt_page_seq = 0;
++ dev->checkpt_byte_count = 0;
++ dev->checkpt_sum = 0;
++ dev->checkpt_xor = 0;
++ dev->checkpt_cur_block = -1;
++ dev->checkpt_cur_chunk = -1;
++ dev->checkpt_next_block = dev->internal_start_block;
++
++ if (writing) {
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++ yaffs2_checkpt_init_chunk_hdr(dev);
++ return yaffs_checkpt_erase(dev);
++ }
++
++ /* Opening for a read */
++ /* Set to a value that will kick off a read */
++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++ /* A checkpoint block list of 1 checkpoint block per 16 block is
++ * (hopefully) going to be way more than we need */
++ dev->blocks_in_checkpt = 0;
++ dev->checkpt_max_blocks =
++ (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
++ dev->checkpt_block_list =
++ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
++
++ if (!dev->checkpt_block_list)
++ return 0;
++
++ for (i = 0; i < dev->checkpt_max_blocks; i++)
++ dev->checkpt_block_list[i] = -1;
++
++ return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++ u32 composite_sum;
++
++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
++ *sum = composite_sum;
++ return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++ int chunk;
++ int offset_chunk;
++ struct yaffs_ext_tags tags;
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_erased_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0)
++ return 0;
++
++ tags.is_deleted = 0;
++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
++ tags.chunk_id = dev->checkpt_page_seq + 1;
++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++ tags.n_bytes = dev->data_bytes_per_chunk;
++ if (dev->checkpt_cur_chunk == 0) {
++ /* First chunk we write for the block? Set block state to
++ checkpoint */
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, dev->checkpt_cur_block);
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ dev->blocks_in_checkpt++;
++ }
++
++ chunk =
++ dev->checkpt_cur_block * dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
++ tags.obj_id, tags.chunk_id);
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++
++ dev->n_page_writes++;
++
++ dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
++ dev->checkpt_buffer, &tags);
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++ dev->checkpt_cur_chunk = 0;
++ dev->checkpt_cur_block = -1;
++ }
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++ yaffs2_checkpt_init_chunk_hdr(dev);
++
++
++ return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (!dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++ ok = yaffs2_checkpt_flush_buffer(dev);
++ }
++
++ return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ struct yaffs_ext_tags tags;
++ int chunk;
++ int offset_chunk;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0) {
++ ok = 0;
++ break;
++ }
++
++ chunk = dev->checkpt_cur_block *
++ dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++ dev->n_page_reads++;
++
++ /* read in the next chunk */
++ dev->tagger.read_chunk_tags_fn(dev,
++ offset_chunk,
++ dev->checkpt_buffer,
++ &tags);
++
++ if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++ ok = 0;
++ break;
++ }
++ if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
++ ok = 0;
++ break;
++ }
++
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++
++ if (dev->checkpt_cur_chunk >=
++ dev->param.chunks_per_block)
++ dev->checkpt_cur_block = -1;
++
++ }
++
++ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++ }
++
++ return i;
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->checkpt_open_write) {
++ if (dev->checkpt_byte_offs !=
++ sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
++ yaffs2_checkpt_flush_buffer(dev);
++ } else if (dev->checkpt_block_list) {
++ for (i = 0;
++ i < dev->blocks_in_checkpt &&
++ dev->checkpt_block_list[i] >= 0; i++) {
++ int blk = dev->checkpt_block_list[i];
++ struct yaffs_block_info *bi = NULL;
++
++ if (dev->internal_start_block <= blk &&
++ blk <= dev->internal_end_block)
++ bi = yaffs_get_block_info(dev, blk);
++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ }
++ kfree(dev->checkpt_block_list);
++ dev->checkpt_block_list = NULL;
++ }
++
++ dev->n_free_chunks -=
++ dev->blocks_in_checkpt * dev->param.chunks_per_block;
++ dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
++ dev->checkpt_byte_count);
++
++ if (dev->checkpt_buffer) {
++ /* free the buffer */
++ kfree(dev->checkpt_buffer);
++ dev->checkpt_buffer = NULL;
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++ /* Erase the checkpoint data */
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint invalidate of %d blocks",
++ dev->blocks_in_checkpt);
++
++ return yaffs_checkpt_erase(dev);
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.10.40/fs/yaffs2/yaffs_checkptrw.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_checkptrw.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_ecc.c linux-3.10.40/fs/yaffs2/yaffs_ecc.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_ecc.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,281 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
++ * such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
++ * and therefore this bytes influence on the line parity.
++ */
++
++static const unsigned char column_parity_table[] = {
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned char line_parity = 0;
++ unsigned char line_parity_prime = 0;
++ unsigned char t;
++ unsigned char b;
++
++ for (i = 0; i < 256; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) { /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++ }
++
++ ecc[2] = (~col_parity) | 0x03;
++
++ t = 0;
++ if (line_parity & 0x80)
++ t |= 0x80;
++ if (line_parity_prime & 0x80)
++ t |= 0x40;
++ if (line_parity & 0x40)
++ t |= 0x20;
++ if (line_parity_prime & 0x40)
++ t |= 0x10;
++ if (line_parity & 0x20)
++ t |= 0x08;
++ if (line_parity_prime & 0x20)
++ t |= 0x04;
++ if (line_parity & 0x10)
++ t |= 0x02;
++ if (line_parity_prime & 0x10)
++ t |= 0x01;
++ ecc[1] = ~t;
++
++ t = 0;
++ if (line_parity & 0x08)
++ t |= 0x80;
++ if (line_parity_prime & 0x08)
++ t |= 0x40;
++ if (line_parity & 0x04)
++ t |= 0x20;
++ if (line_parity_prime & 0x04)
++ t |= 0x10;
++ if (line_parity & 0x02)
++ t |= 0x08;
++ if (line_parity_prime & 0x02)
++ t |= 0x04;
++ if (line_parity & 0x01)
++ t |= 0x02;
++ if (line_parity_prime & 0x01)
++ t |= 0x01;
++ ecc[0] = ~t;
++
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc)
++{
++ unsigned char d0, d1, d2; /* deltas */
++
++ d0 = read_ecc[0] ^ test_ecc[0];
++ d1 = read_ecc[1] ^ test_ecc[1];
++ d2 = read_ecc[2] ^ test_ecc[2];
++
++ if ((d0 | d1 | d2) == 0)
++ return 0; /* no error */
++
++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++ /* Single bit (recoverable) error in data */
++
++ unsigned byte;
++ unsigned bit;
++
++ bit = byte = 0;
++
++ if (d1 & 0x80)
++ byte |= 0x80;
++ if (d1 & 0x20)
++ byte |= 0x40;
++ if (d1 & 0x08)
++ byte |= 0x20;
++ if (d1 & 0x02)
++ byte |= 0x10;
++ if (d0 & 0x80)
++ byte |= 0x08;
++ if (d0 & 0x20)
++ byte |= 0x04;
++ if (d0 & 0x08)
++ byte |= 0x02;
++ if (d0 & 0x02)
++ byte |= 0x01;
++
++ if (d2 & 0x80)
++ bit |= 0x04;
++ if (d2 & 0x20)
++ bit |= 0x02;
++ if (d2 & 0x08)
++ bit |= 0x01;
++
++ data[byte] ^= (1 << bit);
++
++ return 1; /* Corrected the error */
++ }
++
++ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
++ /* Reccoverable error in ecc */
++
++ read_ecc[0] = test_ecc[0];
++ read_ecc[1] = test_ecc[1];
++ read_ecc[2] = test_ecc[2];
++
++ return 1; /* Corrected the error */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc_other)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned line_parity = 0;
++ unsigned line_parity_prime = 0;
++ unsigned char b;
++
++ for (i = 0; i < n_bytes; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) {
++ /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++
++ }
++
++ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++ ecc_other->line_parity = line_parity;
++ ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc)
++{
++ unsigned char delta_col; /* column parity delta */
++ unsigned delta_line; /* line parity delta */
++ unsigned delta_line_prime; /* line parity delta */
++ unsigned bit;
++
++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++ delta_line_prime =
++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++ if ((delta_col | delta_line | delta_line_prime) == 0)
++ return 0; /* no error */
++
++ if (delta_line == ~delta_line_prime &&
++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++ /* Single bit (recoverable) error in data */
++
++ bit = 0;
++
++ if (delta_col & 0x20)
++ bit |= 0x04;
++ if (delta_col & 0x08)
++ bit |= 0x02;
++ if (delta_col & 0x02)
++ bit |= 0x01;
++
++ if (delta_line >= n_bytes)
++ return -1;
++
++ data[delta_line] ^= (1 << bit);
++
++ return 1; /* corrected */
++ }
++
++ if ((hweight32(delta_line) +
++ hweight32(delta_line_prime) +
++ hweight8(delta_col)) == 1) {
++ /* Reccoverable error in ecc */
++
++ *read_ecc = *test_ecc;
++ return 1; /* corrected */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_ecc.h linux-3.10.40/fs/yaffs2/yaffs_ecc.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_ecc.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data.
++ * Thus, two such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++ unsigned char col_parity;
++ unsigned line_parity;
++ unsigned line_parity_prime;
++};
++
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc);
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.10.40/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_getblockinfo.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++ *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs: get_block_info block %d is not valid",
++ blk);
++ BUG();
++ }
++ return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_guts.c linux-3.10.40/fs/yaffs2/yaffs_guts.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_guts.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,5146 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsmarshall.h"
++#include "yaffs_nand.h"
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Forward declarations */
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve);
++
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size);
++
++/* Function to calculate chunk and offset */
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out)
++{
++ int chunk;
++ u32 offset;
++
++ chunk = (u32) (addr >> dev->chunk_shift);
++
++ if (dev->chunk_div == 1) {
++ /* easy power of 2 case */
++ offset = (u32) (addr & dev->chunk_mask);
++ } else {
++ /* Non power-of-2 case */
++
++ loff_t chunk_base;
++
++ chunk /= dev->chunk_div;
++
++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++ offset = (u32) (addr - chunk_base);
++ }
++
++ *chunk_out = chunk;
++ *offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static inline u32 calc_shifts_ceiling(u32 x)
++{
++ int extra_bits;
++ int shifts;
++
++ shifts = extra_bits = 0;
++
++ while (x > 1) {
++ if (x & 1)
++ extra_bits++;
++ x >>= 1;
++ shifts++;
++ }
++
++ if (extra_bits)
++ shifts++;
++
++ return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static inline u32 calc_shifts(u32 x)
++{
++ u32 shifts;
++
++ shifts = 0;
++
++ if (!x)
++ return 0;
++
++ while (!(x & 1)) {
++ x >>= 1;
++ shifts++;
++ }
++
++ return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++ int i;
++ u8 *buf = (u8 *) 1;
++
++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++ dev->temp_buffer[i].in_use = 0;
++ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ dev->temp_buffer[i].buffer = buf;
++ }
++
++ return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
++{
++ int i;
++
++ dev->temp_in_use++;
++ if (dev->temp_in_use > dev->max_temp)
++ dev->max_temp = dev->temp_in_use;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].in_use == 0) {
++ dev->temp_buffer[i].in_use = 1;
++ return dev->temp_buffer[i].buffer;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
++ /*
++ * If we got here then we have to allocate an unmanaged one
++ * This is not good.
++ */
++
++ dev->unmanaged_buffer_allocs++;
++ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
++{
++ int i;
++
++ dev->temp_in_use--;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].buffer == buffer) {
++ dev->temp_buffer[i].in_use = 0;
++ return;
++ }
++ }
++
++ if (buffer) {
++ /* assume it is an unmanaged one. */
++ yaffs_trace(YAFFS_TRACE_BUFFERS,
++ "Releasing unmanaged temp buffer");
++ kfree(buffer);
++ dev->unmanaged_buffer_deallocs++;
++ }
++
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) data;
++ (void) tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++ if (!bi->gc_prioritise) {
++ bi->gc_prioritise = 1;
++ dev->has_pending_prioritised_gc = 1;
++ bi->chunk_error_strikes++;
++
++ if (bi->chunk_error_strikes > 3) {
++ bi->needs_retiring = 1; /* Too many stikes, so retire */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Block struck out");
++
++ }
++ }
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++ int erased_ok)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs_handle_chunk_error(dev, bi);
++
++ if (erased_ok) {
++ /* Was an actual write failure,
++ * so mark the block for retirement.*/
++ bi->needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d needs retiring", flash_block);
++ }
++
++ /* Delete the chunk */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ * Simple hash function. Needs to have a reasonable spread
++ */
++
++static inline int yaffs_hash_fn(int n)
++{
++ if (n < 0)
++ n = -n;
++ return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++ return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++ return dev->lost_n_found;
++}
++
++/*
++ * Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 *buffer, int n_bytes)
++{
++ /* Horrible, slow implementation */
++ while (n_bytes--) {
++ if (*buffer != 0xff)
++ return 0;
++ buffer++;
++ }
++ return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++ int retval = YAFFS_OK;
++ u8 *data = yaffs_get_temp_buffer(dev);
++ struct yaffs_ext_tags tags;
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++ retval = YAFFS_FAIL;
++
++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
++ tags.chunk_used) {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not erased", nand_chunk);
++ retval = YAFFS_FAIL;
++ }
++
++ yaffs_release_temp_buffer(dev, data);
++
++ return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = YAFFS_OK;
++ struct yaffs_ext_tags temp_tags;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++ temp_tags.obj_id != tags->obj_id ||
++ temp_tags.chunk_id != tags->chunk_id ||
++ temp_tags.n_bytes != tags->n_bytes)
++ retval = YAFFS_FAIL;
++
++ yaffs_release_temp_buffer(dev, buffer);
++
++ return retval;
++}
++
++
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
++{
++ int reserved_chunks;
++ int reserved_blocks = dev->param.n_reserved_blocks;
++ int checkpt_blocks;
++
++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
++
++ reserved_chunks =
++ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
++
++ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
++}
++
++static int yaffs_find_alloc_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_block_info *bi;
++
++ if (dev->n_erased_blocks < 1) {
++ /* Hoosterman we've got a problem.
++ * Can't get space to gc
++ */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no more erased blocks");
++
++ return -1;
++ }
++
++ /* Find an empty block. */
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ dev->alloc_block_finder++;
++ if (dev->alloc_block_finder < dev->internal_start_block
++ || dev->alloc_block_finder > dev->internal_end_block) {
++ dev->alloc_block_finder = dev->internal_start_block;
++ }
++
++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->seq_number++;
++ bi->seq_number = dev->seq_number;
++ dev->n_erased_blocks--;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Allocated block %d, seq %d, %d left" ,
++ dev->alloc_block_finder, dev->seq_number,
++ dev->n_erased_blocks);
++ return dev->alloc_block_finder;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs tragedy: no more erased blocks, but there should have been %d",
++ dev->n_erased_blocks);
++
++ return -1;
++}
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++ struct yaffs_block_info **block_ptr)
++{
++ int ret_val;
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block < 0) {
++ /* Get next block to allocate off */
++ dev->alloc_block = yaffs_find_alloc_block(dev);
++ dev->alloc_page = 0;
++ }
++
++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
++ /* No space unless we're allowed to use the reserve. */
++ return -1;
++ }
++
++ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
++ && dev->alloc_page == 0)
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
++
++ /* Next page please.... */
++ if (dev->alloc_block >= 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++
++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
++ dev->alloc_page;
++ bi->pages_in_use++;
++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
++
++ dev->alloc_page++;
++
++ dev->n_free_chunks--;
++
++ /* If the block is full set the state to full */
++ if (dev->alloc_page >= dev->param.chunks_per_block) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ if (block_ptr)
++ *block_ptr = bi;
++
++ return ret_val;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
++
++ return -1;
++}
++
++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
++{
++ int n;
++
++ n = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ if (dev->alloc_block > 0)
++ n += (dev->param.chunks_per_block - dev->alloc_page);
++
++ return n;
++
++}
++
++/*
++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
++{
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block > 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++ }
++}
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++ const u8 *data,
++ struct yaffs_ext_tags *tags, int use_reserver)
++{
++ int attempts = 0;
++ int write_ok = 0;
++ int chunk;
++
++ yaffs2_checkpt_invalidate(dev);
++
++ do {
++ struct yaffs_block_info *bi = 0;
++ int erased_ok = 0;
++
++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
++ if (chunk < 0) {
++ /* no space */
++ break;
++ }
++
++ /* First check this chunk is erased, if it needs
++ * checking. The checking policy (unless forced
++ * always on) is as follows:
++ *
++ * Check the first page we try to write in a block.
++ * If the check passes then we don't need to check any
++ * more. If the check fails, we check again...
++ * If the block has been erased, we don't need to check.
++ *
++ * However, if the block has been prioritised for gc,
++ * then we think there might be something odd about
++ * this block and stop using it.
++ *
++ * Rationale: We should only ever see chunks that have
++ * not been erased if there was a partially written
++ * chunk due to power loss. This checking policy should
++ * catch that case with very few checks and thus save a
++ * lot of checks that are most likely not needed.
++ *
++ * Mods to the above
++ * If an erase check fails or the write fails we skip the
++ * rest of the block.
++ */
++
++ /* let's give it a try */
++ attempts++;
++
++ if (dev->param.always_check_erased)
++ bi->skip_erased_check = 0;
++
++ if (!bi->skip_erased_check) {
++ erased_ok = yaffs_check_chunk_erased(dev, chunk);
++ if (erased_ok != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs chunk %d was not erased",
++ chunk);
++
++ /* If not erased, delete this one,
++ * skip rest of block and
++ * try another chunk */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++ continue;
++ }
++ }
++
++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
++
++ if (!bi->skip_erased_check)
++ write_ok =
++ yaffs_verify_chunk_written(dev, chunk, data, tags);
++
++ if (write_ok != YAFFS_OK) {
++ /* Clean up aborted write, skip to next block and
++ * try another chunk */
++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
++ continue;
++ }
++
++ bi->skip_erased_check = 1;
++
++ /* Copy the data into the robustification buffer */
++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
++
++ } while (write_ok != YAFFS_OK &&
++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++ if (!write_ok)
++ chunk = -1;
++
++ if (attempts > 1) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs write required %d attempts",
++ attempts);
++ dev->n_retried_writes += (attempts - 1);
++ }
++
++ return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to mark bad and erase block %d",
++ flash_block);
++ } else {
++ struct yaffs_ext_tags tags;
++ int chunk_id =
++ flash_block * dev->param.chunks_per_block;
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ memset(&tags, 0, sizeof(tags));
++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
++ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
++ dev->chunk_offset,
++ buffer,
++ &tags) != YAFFS_OK)
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to write bad block marker to block %d",
++ flash_block);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++ }
++
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ bi->gc_prioritise = 0;
++ bi->needs_retiring = 0;
++
++ dev->n_retired_blocks++;
++}
++
++/*---------------- Name handling functions ------------*/
++
++static u16 yaffs_calc_name_sum(const YCHAR *name)
++{
++ u16 sum = 0;
++ u16 i = 1;
++
++ if (!name)
++ return 0;
++
++ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
++
++ /* 0x1f mask is case insensitive */
++ sum += ((*name) & 0x1f) * i;
++ i++;
++ name++;
++ }
++ return sum;
++}
++
++
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
++{
++ memset(obj->short_name, 0, sizeof(obj->short_name));
++
++ if (name && !name[0]) {
++ yaffs_fix_null_name(obj, obj->short_name,
++ YAFFS_SHORT_NAME_LENGTH);
++ name = obj->short_name;
++ } else if (name &&
++ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
++ YAFFS_SHORT_NAME_LENGTH) {
++ strcpy(obj->short_name, name);
++ }
++
++ obj->sum = yaffs_calc_name_sum(name);
++}
++
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
++ memset(tmp_name, 0, sizeof(tmp_name));
++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_set_obj_name(obj, tmp_name);
++#else
++ yaffs_set_obj_name(obj, oh->name);
++#endif
++}
++
++loff_t yaffs_max_file_size(struct yaffs_dev *dev)
++{
++ if(sizeof(loff_t) < 8)
++ return YAFFS_MAX_FILE_SIZE_32;
++ else
++ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
++
++ if (tn) {
++ memset(tn, 0, dev->tnode_size);
++ dev->n_tnodes++;
++ }
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ yaffs_free_raw_tnode(dev, tn);
++ dev->n_tnodes--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ yaffs_deinit_raw_tnodes_and_objs(dev);
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++}
++
++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos, unsigned val)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 mask;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++ val >>= dev->chunk_grp_bits;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ mask = dev->tnode_mask << bit_in_word;
++
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val << bit_in_word));
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ mask =
++ dev->tnode_mask >> bit_in_word;
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val >> bit_in_word));
++ }
++}
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 val;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ val = map[word_in_map] >> bit_in_word;
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ val |= (map[word_in_map] << bit_in_word);
++ }
++
++ val &= dev->tnode_mask;
++ val <<= dev->chunk_grp_bits;
++
++ return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of top_level
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id)
++{
++ struct yaffs_tnode *tn = file_struct->top;
++ u32 i;
++ int required_depth;
++ int level = file_struct->top_level;
++
++ (void) dev;
++
++ /* Check sane level and chunk Id */
++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (i) {
++ i >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level)
++ return NULL; /* Not tall enough, so we can't find it */
++
++ /* Traverse down to level 0 */
++ while (level > 0 && tn) {
++ tn = tn->internal[(chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (level - 1) *
++ YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK];
++ level--;
++ }
++
++ return tn;
++}
++
++/* add_find_tnode_0 finds the level 0 tnode if it exists,
++ * otherwise first expands the tree.
++ * This happens in two steps:
++ * 1. If the tree isn't tall enough, then make it taller.
++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the
++ * specified tn will be plugged into the ttree.
++ */
++
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn)
++{
++ int required_depth;
++ int i;
++ int l;
++ struct yaffs_tnode *tn;
++ u32 x;
++
++ /* Check sane level and page Id */
++ if (file_struct->top_level < 0 ||
++ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level) {
++ /* Not tall enough, gotta make the tree taller */
++ for (i = file_struct->top_level; i < required_depth; i++) {
++
++ tn = yaffs_get_tnode(dev);
++
++ if (tn) {
++ tn->internal[0] = file_struct->top;
++ file_struct->top = tn;
++ file_struct->top_level++;
++ } else {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: no more tnodes");
++ return NULL;
++ }
++ }
++ }
++
++ /* Traverse down to level 0, adding anything we need */
++
++ l = file_struct->top_level;
++ tn = file_struct->top;
++
++ if (l > 0) {
++ while (l > 0 && tn) {
++ x = (chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK;
++
++ if ((l > 1) && !tn->internal[x]) {
++ /* Add missing non-level-zero tnode */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ } else if (l == 1) {
++ /* Looking from level 1 at level 0 */
++ if (passed_tn) {
++ /* If we already have one, release it */
++ if (tn->internal[x])
++ yaffs_free_tnode(dev,
++ tn->internal[x]);
++ tn->internal[x] = passed_tn;
++
++ } else if (!tn->internal[x]) {
++ /* Don't have one, none passed in */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ }
++ }
++
++ tn = tn->internal[x];
++ l--;
++ }
++ } else {
++ /* top is level 0 */
++ if (passed_tn) {
++ memcpy(tn, passed_tn,
++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
++ yaffs_free_tnode(dev, passed_tn);
++ }
++ }
++
++ return tn;
++}
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++ int chunk_obj)
++{
++ return (tags->chunk_id == chunk_obj &&
++ tags->obj_id == obj_id &&
++ !tags->is_deleted) ? 1 : 0;
++
++}
++
++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
++ struct yaffs_ext_tags *tags, int obj_id,
++ int inode_chunk)
++{
++ int j;
++
++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
++ if (yaffs_check_chunk_bit
++ (dev, the_chunk / dev->param.chunks_per_block,
++ the_chunk % dev->param.chunks_per_block)) {
++
++ if (dev->chunk_grp_size == 1)
++ return the_chunk;
++ else {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ tags);
++ if (yaffs_tags_match(tags,
++ obj_id, inode_chunk)) {
++ /* found it; */
++ return the_chunk;
++ }
++ }
++ }
++ the_chunk++;
++ }
++ return -1;
++}
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /*Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ int ret_val = -1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++ return ret_val;
++}
++
++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /* Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ struct yaffs_dev *dev = in->my_dev;
++ int ret_val = -1;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++
++ /* Delete the entry in the filestructure (if found) */
++ if (ret_val != -1)
++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
++
++ return ret_val;
++}
++
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan)
++{
++ /* NB in_scan is zero unless scanning.
++ * For forward scanning, in_scan is > 0;
++ * for backward scanning in_scan is < 0
++ *
++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
++ */
++
++ struct yaffs_tnode *tn;
++ struct yaffs_dev *dev = in->my_dev;
++ int existing_cunk;
++ struct yaffs_ext_tags existing_tags;
++ struct yaffs_ext_tags new_tags;
++ unsigned existing_serial, new_serial;
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
++ /* Just ignore an attempt at putting a chunk into a non-file
++ * during scanning.
++ * If it is not during Scanning then something went wrong!
++ */
++ if (!in_scan) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy:attempt to put data chunk into a non-file"
++ );
++ BUG();
++ }
++
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++
++ tn = yaffs_add_find_tnode_0(dev,
++ &in->variant.file_variant,
++ inode_chunk, NULL);
++ if (!tn)
++ return YAFFS_FAIL;
++
++ if (!nand_chunk)
++ /* Dummy insert, bail now */
++ return YAFFS_OK;
++
++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ if (in_scan != 0) {
++ /* If we're scanning then we need to test for duplicates
++ * NB This does not need to be efficient since it should only
++ * happen when the power fails during a write, then only one
++ * chunk should ever be affected.
++ *
++ * Correction for YAFFS2: This could happen quite a lot and we
++ * need to think about efficiency! TODO
++ * Update: For backward scanning we don't need to re-read tags
++ * so this is quite cheap.
++ */
++
++ if (existing_cunk > 0) {
++ /* NB Right now existing chunk will not be real
++ * chunk_id if the chunk group size > 1
++ * thus we have to do a FindChunkInFile to get the
++ * real chunk id.
++ *
++ * We have a duplicate now we need to decide which
++ * one to use:
++ *
++ * Backwards scanning YAFFS2: The old one is what
++ * we use, dump the new one.
++ * YAFFS1: Get both sets of tags and compare serial
++ * numbers.
++ */
++
++ if (in_scan > 0) {
++ /* Only do this for forward scanning */
++ yaffs_rd_chunk_tags_nand(dev,
++ nand_chunk,
++ NULL, &new_tags);
++
++ /* Do a proper find */
++ existing_cunk =
++ yaffs_find_chunk_in_file(in, inode_chunk,
++ &existing_tags);
++ }
++
++ if (existing_cunk <= 0) {
++ /*Hoosterman - how did this happen? */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: existing chunk < 0 in scan"
++ );
++
++ }
++
++ /* NB The deleted flags should be false, otherwise
++ * the chunks will not be loaded during a scan
++ */
++
++ if (in_scan > 0) {
++ new_serial = new_tags.serial_number;
++ existing_serial = existing_tags.serial_number;
++ }
++
++ if ((in_scan > 0) &&
++ (existing_cunk <= 0 ||
++ ((existing_serial + 1) & 3) == new_serial)) {
++ /* Forward scanning.
++ * Use new
++ * Delete the old one and drop through to
++ * update the tnode
++ */
++ yaffs_chunk_del(dev, existing_cunk, 1,
++ __LINE__);
++ } else {
++ /* Backward scanning or we want to use the
++ * existing one
++ * Delete the new one and return early so that
++ * the tnode isn't changed
++ */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++ }
++
++ }
++
++ if (existing_cunk == 0)
++ in->n_data_chunks++;
++
++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
++
++ return YAFFS_OK;
++}
++
++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
++{
++ struct yaffs_block_info *the_block;
++ unsigned block_no;
++
++ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
++
++ block_no = chunk / dev->param.chunks_per_block;
++ the_block = yaffs_get_block_info(dev, block_no);
++ if (the_block) {
++ the_block->soft_del_pages++;
++ dev->n_free_chunks++;
++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
++ }
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
++ * the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls
++ * the chunk out of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks
++ * are soft deleted.
++ */
++
++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
++ u32 level, int chunk_offset)
++{
++ int i;
++ int the_chunk;
++ int all_done = 1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = YAFFS_NTNODES_INTERNAL - 1;
++ all_done && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ all_done =
++ yaffs_soft_del_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ if (all_done) {
++ yaffs_free_tnode(dev,
++ tn->internal[i]);
++ tn->internal[i] = NULL;
++ } else {
++ /* Can this happen? */
++ }
++ }
++ }
++ return (all_done) ? 1 : 0;
++ }
++
++ /* level 0 */
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk) {
++ yaffs_soft_del_chunk(dev, the_chunk);
++ yaffs_load_tnode_0(dev, tn, i, 0);
++ }
++ }
++ return 1;
++}
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_obj *parent;
++
++ yaffs_verify_obj_in_dir(obj);
++ parent = obj->parent;
++
++ yaffs_verify_dir(parent);
++
++ if (dev && dev->param.remove_obj_fn)
++ dev->param.remove_obj_fn(obj);
++
++ list_del_init(&obj->siblings);
++ obj->parent = NULL;
++
++ yaffs_verify_dir(parent);
++}
++
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
++{
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a null pointer directory"
++ );
++ BUG();
++ return;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a non-directory"
++ );
++ BUG();
++ }
++
++ if (obj->siblings.prev == NULL) {
++ /* Not initialised */
++ BUG();
++ }
++
++ yaffs_verify_dir(directory);
++
++ yaffs_remove_obj_from_dir(obj);
++
++ /* Now add it */
++ list_add(&obj->siblings, &directory->variant.dir_variant.children);
++ obj->parent = directory;
++
++ if (directory == obj->my_dev->unlinked_dir
++ || directory == obj->my_dev->del_dir) {
++ obj->unlinked = 1;
++ obj->my_dev->n_unlinked_files++;
++ obj->rename_allowed = 0;
++ }
++
++ yaffs_verify_dir(directory);
++ yaffs_verify_obj_in_dir(obj);
++}
++
++static int yaffs_change_obj_name(struct yaffs_obj *obj,
++ struct yaffs_obj *new_dir,
++ const YCHAR *new_name, int force, int shadows)
++{
++ int unlink_op;
++ int del_op;
++ struct yaffs_obj *existing_target;
++
++ if (new_dir == NULL)
++ new_dir = obj->parent; /* use the old directory */
++
++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_change_obj_name: new_dir is not a directory"
++ );
++ BUG();
++ }
++
++ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
++ del_op = (new_dir == obj->my_dev->del_dir);
++
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++
++ /* If the object is a file going into the unlinked directory,
++ * then it is OK to just stuff it in since duplicate names are OK.
++ * else only proceed if the new name does not exist and we're putting
++ * it into a directory.
++ */
++ if (!(unlink_op || del_op || force ||
++ shadows > 0 || !existing_target) ||
++ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ return YAFFS_FAIL;
++
++ yaffs_set_obj_name(obj, new_name);
++ obj->dirty = 1;
++ yaffs_add_obj_to_dir(new_dir, obj);
++
++ if (unlink_op)
++ obj->unlinked = 1;
++
++ /* If it is a deletion then we mark it as a shrink for gc */
++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++/*------------------------ Short Operations Cache ------------------------------
++ * In many situations where there is no high level buffering a lot of
++ * reads might be short sequential reads, and a lot of writes may be short
++ * sequential writes. eg. scanning/writing a jpeg file.
++ * In these cases, a short read/write cache can provide a huge perfomance
++ * benefit with dumb-as-a-rock code.
++ * In Linux, the page cache provides read buffering and the short op cache
++ * provides write buffering.
++ *
++ * There are a small number (~10) of cache chunks per device so that we don't
++ * need a very intelligent search.
++ */
++
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++ struct yaffs_cache *cache;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ for (i = 0; i < n_caches; i++) {
++ cache = &dev->cache[i];
++ if (cache->object == obj && cache->dirty)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void yaffs_flush_file_cache(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int lowest = -99; /* Stop compiler whining. */
++ int i;
++ struct yaffs_cache *cache;
++ int chunk_written = 0;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ if (n_caches < 1)
++ return;
++ do {
++ cache = NULL;
++
++ /* Find the lowest dirty chunk for this object */
++ for (i = 0; i < n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].dirty) {
++ if (!cache ||
++ dev->cache[i].chunk_id < lowest) {
++ cache = &dev->cache[i];
++ lowest = cache->chunk_id;
++ }
++ }
++ }
++
++ if (cache && !cache->locked) {
++ /* Write it out and free it up */
++ chunk_written =
++ yaffs_wr_data_obj(cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ cache->object = NULL;
++ }
++ } while (cache && chunk_written > 0);
++
++ if (cache)
++ /* Hoosterman, disk full while writing cache out. */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no space during cache write");
++}
++
++/*yaffs_flush_whole_cache(dev)
++ *
++ *
++ */
++
++void yaffs_flush_whole_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int n_caches = dev->param.n_caches;
++ int i;
++
++ /* Find a dirty object in the cache and flush it...
++ * until there are no further dirty objects.
++ */
++ do {
++ obj = NULL;
++ for (i = 0; i < n_caches && !obj; i++) {
++ if (dev->cache[i].object && dev->cache[i].dirty)
++ obj = dev->cache[i].object;
++ }
++ if (obj)
++ yaffs_flush_file_cache(obj);
++ } while (obj);
++
++}
++
++/* Grab us a cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->param.n_caches > 0) {
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (!dev->cache[i].object)
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_cache *cache;
++ struct yaffs_obj *the_obj;
++ int usage;
++ int i;
++ int pushout;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ /* Try find a non-dirty one... */
++
++ cache = yaffs_grab_chunk_worker(dev);
++
++ if (!cache) {
++ /* They were all dirty, find the LRU object and flush
++ * its cache, then find again.
++ * NB what's here is not very accurate,
++ * we actually flush the object with the LRU chunk.
++ */
++
++ /* With locking we can't assume we can use entry zero,
++ * Set the_obj to a valid pointer for Coverity. */
++ the_obj = dev->cache[0].object;
++ usage = -1;
++ cache = NULL;
++ pushout = -1;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object &&
++ !dev->cache[i].locked &&
++ (dev->cache[i].last_use < usage ||
++ !cache)) {
++ usage = dev->cache[i].last_use;
++ the_obj = dev->cache[i].object;
++ cache = &dev->cache[i];
++ pushout = i;
++ }
++ }
++
++ if (!cache || cache->dirty) {
++ /* Flush and try again */
++ yaffs_flush_file_cache(the_obj);
++ cache = yaffs_grab_chunk_worker(dev);
++ }
++ }
++ return cache;
++}
++
++/* Find a cached chunk */
++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
++ int chunk_id)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].chunk_id == chunk_id) {
++ dev->cache_hits++;
++
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
++ int is_write)
++{
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return;
++
++ if (dev->cache_last_use < 0 ||
++ dev->cache_last_use > 100000000) {
++ /* Reset the cache usages */
++ for (i = 1; i < dev->param.n_caches; i++)
++ dev->cache[i].last_use = 0;
++
++ dev->cache_last_use = 0;
++ }
++ dev->cache_last_use++;
++ cache->last_use = dev->cache_last_use;
++
++ if (is_write)
++ cache->dirty = 1;
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
++{
++ struct yaffs_cache *cache;
++
++ if (object->my_dev->param.n_caches > 0) {
++ cache = yaffs_find_chunk_cache(object, chunk_id);
++
++ if (cache)
++ cache->object = NULL;
++ }
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.n_caches > 0) {
++ /* Invalidate it. */
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == in)
++ dev->cache[i].object = NULL;
++ }
++ }
++}
++
++static void yaffs_unhash_obj(struct yaffs_obj *obj)
++{
++ int bucket;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ /* If it is still linked into the bucket list, free from the list */
++ if (!list_empty(&obj->hash_link)) {
++ list_del_init(&obj->hash_link);
++ bucket = yaffs_hash_fn(obj->obj_id);
++ dev->obj_bucket[bucket].count--;
++ }
++}
++
++/* FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_free_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj) {
++ BUG();
++ return;
++ }
++ dev = obj->my_dev;
++ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
++ obj, obj->my_inode);
++ if (obj->parent)
++ BUG();
++ if (!list_empty(&obj->siblings))
++ BUG();
++
++ if (obj->my_inode) {
++ /* We're still hooked up to a cached inode.
++ * Don't delete now, but mark for later deletion
++ */
++ obj->defered_free = 1;
++ return;
++ }
++
++ yaffs_unhash_obj(obj);
++
++ yaffs_free_raw_obj(dev, obj);
++ dev->n_obj--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj)
++{
++ if (obj->defered_free)
++ yaffs_free_obj(obj);
++}
++
++static int yaffs_generic_obj_del(struct yaffs_obj *in)
++{
++ /* Iinvalidate the file's data in the cache, without flushing. */
++ yaffs_invalidate_whole_cache(in);
++
++ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
++ /* Move to unlinked directory so we have a deletion record */
++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
++ 0);
++ }
++
++ yaffs_remove_obj_from_dir(in);
++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
++ in->hdr_chunk = 0;
++
++ yaffs_free_obj(in);
++ return YAFFS_OK;
++
++}
++
++static void yaffs_soft_del_file(struct yaffs_obj *obj)
++{
++ if (!obj->deleted ||
++ obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
++ obj->soft_del)
++ return;
++
++ if (obj->n_data_chunks <= 0) {
++ /* Empty file with no duplicate object headers,
++ * just delete it immediately */
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: Deleting empty file %d",
++ obj->obj_id);
++ yaffs_generic_obj_del(obj);
++ } else {
++ yaffs_soft_del_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.
++ file_variant.top_level, 0);
++ obj->soft_del = 1;
++ }
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
++ struct yaffs_tnode *tn, u32 level,
++ int del0)
++{
++ int i;
++ int has_data;
++
++ if (!tn)
++ return tn;
++
++ has_data = 0;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i]) {
++ tn->internal[i] =
++ yaffs_prune_worker(dev,
++ tn->internal[i],
++ level - 1,
++ (i == 0) ? del0 : 1);
++ }
++
++ if (tn->internal[i])
++ has_data++;
++ }
++ } else {
++ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
++ u32 *map = (u32 *) tn;
++
++ for (i = 0; !has_data && i < tnode_size_u32; i++) {
++ if (map[i])
++ has_data++;
++ }
++ }
++
++ if (has_data == 0 && del0) {
++ /* Free and return NULL */
++ yaffs_free_tnode(dev, tn);
++ tn = NULL;
++ }
++ return tn;
++}
++
++static int yaffs_prune_tree(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct)
++{
++ int i;
++ int has_data;
++ int done = 0;
++ struct yaffs_tnode *tn;
++
++ if (file_struct->top_level < 1)
++ return YAFFS_OK;
++
++ file_struct->top =
++ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
++
++ /* Now we have a tree with all the non-zero branches NULL but
++ * the height is the same as it was.
++ * Let's see if we can trim internal tnodes to shorten the tree.
++ * We can do this if only the 0th element in the tnode is in use
++ * (ie all the non-zero are NULL)
++ */
++
++ while (file_struct->top_level && !done) {
++ tn = file_struct->top;
++
++ has_data = 0;
++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i])
++ has_data++;
++ }
++
++ if (!has_data) {
++ file_struct->top = tn->internal[0];
++ file_struct->top_level--;
++ yaffs_free_tnode(dev, tn);
++ } else {
++ done = 1;
++ }
++ }
++
++ return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* alloc_empty_obj gets us a clean Object.*/
++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
++
++ if (!obj)
++ return obj;
++
++ dev->n_obj++;
++
++ /* Now sweeten it up... */
++
++ memset(obj, 0, sizeof(struct yaffs_obj));
++ obj->being_created = 1;
++
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0;
++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
++ INIT_LIST_HEAD(&(obj->hard_links));
++ INIT_LIST_HEAD(&(obj->hash_link));
++ INIT_LIST_HEAD(&obj->siblings);
++
++ /* Now make the directory sane */
++ if (dev->root_dir) {
++ obj->parent = dev->root_dir;
++ list_add(&(obj->siblings),
++ &dev->root_dir->variant.dir_variant.children);
++ }
++
++ /* Add it to the lost and found directory.
++ * NB Can't put root or lost-n-found in lost-n-found so
++ * check if lost-n-found exists first
++ */
++ if (dev->lost_n_found)
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++
++ obj->being_created = 0;
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return obj;
++}
++
++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
++{
++ int i;
++ int l = 999;
++ int lowest = 999999;
++
++ /* Search for the shortest list or one that
++ * isn't too long.
++ */
++
++ for (i = 0; i < 10 && lowest > 4; i++) {
++ dev->bucket_finder++;
++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
++ lowest = dev->obj_bucket[dev->bucket_finder].count;
++ l = dev->bucket_finder;
++ }
++ }
++
++ return l;
++}
++
++static int yaffs_new_obj_id(struct yaffs_dev *dev)
++{
++ int bucket = yaffs_find_nice_bucket(dev);
++ int found = 0;
++ struct list_head *i;
++ u32 n = (u32) bucket;
++
++ /* Now find an object value that has not already been taken
++ * by scanning the list.
++ */
++
++ while (!found) {
++ found = 1;
++ n += YAFFS_NOBJECT_BUCKETS;
++ if (1 || dev->obj_bucket[bucket].count > 0) {
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* If there is already one in the list */
++ if (i && list_entry(i, struct yaffs_obj,
++ hash_link)->obj_id == n) {
++ found = 0;
++ }
++ }
++ }
++ }
++ return n;
++}
++
++static void yaffs_hash_obj(struct yaffs_obj *in)
++{
++ int bucket = yaffs_hash_fn(in->obj_id);
++ struct yaffs_dev *dev = in->my_dev;
++
++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
++ dev->obj_bucket[bucket].count++;
++}
++
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
++{
++ int bucket = yaffs_hash_fn(number);
++ struct list_head *i;
++ struct yaffs_obj *in;
++
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* Look if it is in the list */
++ in = list_entry(i, struct yaffs_obj, hash_link);
++ if (in->obj_id == number) {
++ /* Don't show if it is defered free */
++ if (in->defered_free)
++ return NULL;
++ return in;
++ }
++ }
++
++ return NULL;
++}
++
++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++ struct yaffs_tnode *tn = NULL;
++
++ if (number < 0)
++ number = yaffs_new_obj_id(dev);
++
++ if (type == YAFFS_OBJECT_TYPE_FILE) {
++ tn = yaffs_get_tnode(dev);
++ if (!tn)
++ return NULL;
++ }
++
++ the_obj = yaffs_alloc_empty_obj(dev);
++ if (!the_obj) {
++ if (tn)
++ yaffs_free_tnode(dev, tn);
++ return NULL;
++ }
++
++ the_obj->fake = 0;
++ the_obj->rename_allowed = 1;
++ the_obj->unlink_allowed = 1;
++ the_obj->obj_id = number;
++ yaffs_hash_obj(the_obj);
++ the_obj->variant_type = type;
++ yaffs_load_current_time(the_obj, 1, 1);
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ the_obj->variant.file_variant.file_size = 0;
++ the_obj->variant.file_variant.scanned_size = 0;
++ the_obj->variant.file_variant.shrink_size =
++ yaffs_max_file_size(dev);
++ the_obj->variant.file_variant.top_level = 0;
++ the_obj->variant.file_variant.top = tn;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* No action required */
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* todo this should not happen */
++ break;
++ }
++ return the_obj;
++}
++
++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
++ int number, u32 mode)
++{
++
++ struct yaffs_obj *obj =
++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++
++ if (!obj)
++ return NULL;
++
++ obj->fake = 1; /* it is fake so it might not use NAND */
++ obj->rename_allowed = 0;
++ obj->unlink_allowed = 0;
++ obj->deleted = 0;
++ obj->unlinked = 0;
++ obj->yst_mode = mode;
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0; /* Not a valid chunk. */
++ return obj;
++
++}
++
++
++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ int i;
++
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++ yaffs_init_raw_tnodes_and_objs(dev);
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
++ dev->obj_bucket[i].count = 0;
++ }
++}
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++
++ if (number > 0)
++ the_obj = yaffs_find_by_number(dev, number);
++
++ if (!the_obj)
++ the_obj = yaffs_new_obj(dev, number, type);
++
++ return the_obj;
++
++}
++
++YCHAR *yaffs_clone_str(const YCHAR *str)
++{
++ YCHAR *new_str = NULL;
++ int len;
++
++ if (!str)
++ str = _Y("");
++
++ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
++ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
++ if (new_str) {
++ strncpy(new_str, str, len);
++ new_str[len] = 0;
++ }
++ return new_str;
++
++}
++/*
++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ * create dir/a : update dir's mtime/ctime
++ * rm dir/a: update dir's mtime/ctime
++ * modify dir/a: don't update dir's mtimme/ctime
++ *
++ * This can be handled immediately or defered. Defering helps reduce the number
++ * of updates when many files in a directory are changed within a brief period.
++ *
++ * If the directory updating is defered then yaffs_update_dirty_dirs must be
++ * called periodically.
++ */
++
++static void yaffs_update_parent(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj)
++ return;
++ dev = obj->my_dev;
++ obj->dirty = 1;
++ yaffs_load_current_time(obj, 0, 1);
++ if (dev->param.defered_dir_update) {
++ struct list_head *link = &obj->variant.dir_variant.dirty;
++
++ if (list_empty(link)) {
++ list_add(link, &dev->dirty_dirs);
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Added object %d to dirty directories",
++ obj->obj_id);
++ }
++
++ } else {
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
++{
++ struct list_head *link;
++ struct yaffs_obj *obj;
++ struct yaffs_dir_var *d_s;
++ union yaffs_obj_var *o_v;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
++
++ while (!list_empty(&dev->dirty_dirs)) {
++ link = dev->dirty_dirs.next;
++ list_del_init(link);
++
++ d_s = list_entry(link, struct yaffs_dir_var, dirty);
++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
++ obj = list_entry(o_v, struct yaffs_obj, variant);
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
++ obj->obj_id);
++
++ if (obj->dirty)
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++/*
++ * Mknod (create) a new object.
++ * equiv_obj only has meaning for a hard link;
++ * alias_str only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
++ struct yaffs_obj *parent,
++ const YCHAR *name,
++ u32 mode,
++ u32 uid,
++ u32 gid,
++ struct yaffs_obj *equiv_obj,
++ const YCHAR *alias_str, u32 rdev)
++{
++ struct yaffs_obj *in;
++ YCHAR *str = NULL;
++ struct yaffs_dev *dev = parent->my_dev;
++
++ /* Check if the entry exists.
++ * If it does then fail the call since we don't want a dup. */
++ if (yaffs_find_by_name(parent, name))
++ return NULL;
++
++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ str = yaffs_clone_str(alias_str);
++ if (!str)
++ return NULL;
++ }
++
++ in = yaffs_new_obj(dev, -1, type);
++
++ if (!in) {
++ kfree(str);
++ return NULL;
++ }
++
++ in->hdr_chunk = 0;
++ in->valid = 1;
++ in->variant_type = type;
++
++ in->yst_mode = mode;
++
++ yaffs_attribs_init(in, gid, uid, rdev);
++
++ in->n_data_chunks = 0;
++
++ yaffs_set_obj_name(in, name);
++ in->dirty = 1;
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ in->my_dev = parent->my_dev;
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.alias = str;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardlink_variant.equiv_obj = equiv_obj;
++ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
++ list_add(&in->hard_links, &equiv_obj->hard_links);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* do nothing */
++ break;
++ }
++
++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
++ /* Could not create the object header, fail */
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ if (in)
++ yaffs_update_parent(parent);
++
++ return in;
++}
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++ uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++ mode, uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++ uid, gid, NULL, NULL, rdev);
++}
++
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++ uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_link_obj returns the object id of the equivalent object.*/
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++ struct yaffs_obj *equiv_obj)
++{
++ /* Get the real object in case we were fed a hard link obj */
++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
++
++ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
++ parent, name, 0, 0, 0,
++ equiv_obj, NULL, 0))
++ return equiv_obj;
++
++ return NULL;
++
++}
++
++
++
++/*---------------------- Block Management and Page Allocation -------------*/
++
++static void yaffs_deinit_blocks(struct yaffs_dev *dev)
++{
++ if (dev->block_info_alt && dev->block_info)
++ vfree(dev->block_info);
++ else
++ kfree(dev->block_info);
++
++ dev->block_info_alt = 0;
++
++ dev->block_info = NULL;
++
++ if (dev->chunk_bits_alt && dev->chunk_bits)
++ vfree(dev->chunk_bits);
++ else
++ kfree(dev->chunk_bits);
++ dev->chunk_bits_alt = 0;
++ dev->chunk_bits = NULL;
++}
++
++static int yaffs_init_blocks(struct yaffs_dev *dev)
++{
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ dev->block_info = NULL;
++ dev->chunk_bits = NULL;
++ dev->alloc_block = -1; /* force it to get a new one */
++
++ /* If the first allocation strategy fails, thry the alternate one */
++ dev->block_info =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
++ if (!dev->block_info) {
++ dev->block_info =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_info));
++ dev->block_info_alt = 1;
++ } else {
++ dev->block_info_alt = 0;
++ }
++
++ if (!dev->block_info)
++ goto alloc_error;
++
++ /* Set up dynamic blockinfo stuff. Round up bytes. */
++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
++ dev->chunk_bits =
++ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
++ if (!dev->chunk_bits) {
++ dev->chunk_bits =
++ vmalloc(dev->chunk_bit_stride * n_blocks);
++ dev->chunk_bits_alt = 1;
++ } else {
++ dev->chunk_bits_alt = 0;
++ }
++ if (!dev->chunk_bits)
++ goto alloc_error;
++
++
++ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
++ return YAFFS_OK;
++
++alloc_error:
++ yaffs_deinit_blocks(dev);
++ return YAFFS_FAIL;
++}
++
++
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
++ int erased_ok = 0;
++ int i;
++
++ /* If the block is still healthy erase it and mark as clean.
++ * If the block has had a data failure, then retire it.
++ */
++
++ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++ "yaffs_block_became_dirty block %d state %d %s",
++ block_no, bi->block_state,
++ (bi->needs_retiring) ? "needs retiring" : "");
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
++
++ /* If this is the block being garbage collected then stop gc'ing */
++ if (block_no == dev->gc_block)
++ dev->gc_block = 0;
++
++ /* If this block is currently the best candidate for gc
++ * then drop as a candidate */
++ if (block_no == dev->gc_dirtiest) {
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ }
++
++ if (!bi->needs_retiring) {
++ yaffs2_checkpt_invalidate(dev);
++ erased_ok = yaffs_erase_block(dev, block_no);
++ if (!erased_ok) {
++ dev->n_erase_failures++;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Erasure failed %d", block_no);
++ }
++ }
++
++ /* Verify erasure if needed */
++ if (erased_ok &&
++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
++ !yaffs_skip_verification(dev))) {
++ for (i = 0; i < dev->param.chunks_per_block; i++) {
++ if (!yaffs_check_chunk_erased(dev,
++ block_no * dev->param.chunks_per_block + i)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ ">>Block %d erasure supposedly OK, but chunk %d not erased",
++ block_no, i);
++ }
++ }
++ }
++
++ if (!erased_ok) {
++ /* We lost a block of free space */
++ dev->n_free_chunks -= dev->param.chunks_per_block;
++ yaffs_retire_block(dev, block_no);
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d retired", block_no);
++ return;
++ }
++
++ /* Clean it up... */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ bi->seq_number = 0;
++ dev->n_erased_blocks++;
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++ bi->has_shrink_hdr = 0;
++ bi->skip_erased_check = 1; /* Clean, so no need to check */
++ bi->gc_prioritise = 0;
++ bi->has_summary = 0;
++
++ yaffs_clear_chunk_bits(dev, block_no);
++
++ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
++}
++
++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int old_chunk, u8 *buffer)
++{
++ int new_chunk;
++ int mark_flash = 1;
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj *object;
++ int matching_chunk;
++ int ret_val = YAFFS_OK;
++
++ memset(&tags, 0, sizeof(tags));
++ yaffs_rd_chunk_tags_nand(dev, old_chunk,
++ buffer, &tags);
++ object = yaffs_find_by_number(dev, tags.obj_id);
++
++ yaffs_trace(YAFFS_TRACE_GC_DETAIL,
++ "Collecting chunk in block %d, %d %d %d ",
++ dev->gc_chunk, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++
++ if (object && !yaffs_skip_verification(dev)) {
++ if (tags.chunk_id == 0)
++ matching_chunk =
++ object->hdr_chunk;
++ else if (object->soft_del)
++ /* Defeat the test */
++ matching_chunk = old_chunk;
++ else
++ matching_chunk =
++ yaffs_find_chunk_in_file
++ (object, tags.chunk_id,
++ NULL);
++
++ if (old_chunk != matching_chunk)
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "gc: page in gc mismatch: %d %d %d %d",
++ old_chunk,
++ matching_chunk,
++ tags.obj_id,
++ tags.chunk_id);
++ }
++
++ if (!object) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "page %d in gc has no object: %d %d %d ",
++ old_chunk,
++ tags.obj_id, tags.chunk_id,
++ tags.n_bytes);
++ }
++
++ if (object &&
++ object->deleted &&
++ object->soft_del && tags.chunk_id != 0) {
++ /* Data chunk in a soft deleted file,
++ * throw it away.
++ * It's a soft deleted data chunk,
++ * No need to copy this, just forget
++ * about it and fix up the object.
++ */
++
++ /* Free chunks already includes
++ * softdeleted chunks, how ever this
++ * chunk is going to soon be really
++ * deleted which will increment free
++ * chunks. We have to decrement free
++ * chunks so this works out properly.
++ */
++ dev->n_free_chunks--;
++ bi->soft_del_pages--;
++
++ object->n_data_chunks--;
++ if (object->n_data_chunks <= 0) {
++ /* remeber to clean up obj */
++ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
++ dev->n_clean_ups++;
++ }
++ mark_flash = 0;
++ } else if (object) {
++ /* It's either a data chunk in a live
++ * file or an ObjectHeader, so we're
++ * interested in it.
++ * NB Need to keep the ObjectHeaders of
++ * deleted files until the whole file
++ * has been deleted off
++ */
++ tags.serial_number++;
++ dev->n_gc_copies++;
++
++ if (tags.chunk_id == 0) {
++ /* It is an object Id,
++ * We need to nuke the
++ * shrinkheader flags since its
++ * work is done.
++ * Also need to clean up
++ * shadowing.
++ */
++ struct yaffs_obj_hdr *oh;
++ oh = (struct yaffs_obj_hdr *) buffer;
++
++ oh->is_shrink = 0;
++ tags.extra_is_shrink = 0;
++ oh->shadows_obj = 0;
++ oh->inband_shadowed_obj_id = 0;
++ tags.extra_shadows = 0;
++
++ /* Update file size */
++ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++ yaffs_oh_size_load(oh,
++ object->variant.file_variant.file_size);
++ tags.extra_file_size =
++ object->variant.file_variant.file_size;
++ }
++
++ yaffs_verify_oh(object, oh, &tags, 1);
++ new_chunk =
++ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
++ } else {
++ new_chunk =
++ yaffs_write_new_chunk(dev, buffer, &tags, 1);
++ }
++
++ if (new_chunk < 0) {
++ ret_val = YAFFS_FAIL;
++ } else {
++
++ /* Now fix up the Tnodes etc. */
++
++ if (tags.chunk_id == 0) {
++ /* It's a header */
++ object->hdr_chunk = new_chunk;
++ object->serial = tags.serial_number;
++ } else {
++ /* It's a data chunk */
++ yaffs_put_chunk_in_file(object, tags.chunk_id,
++ new_chunk, 0);
++ }
++ }
++ }
++ if (ret_val == YAFFS_OK)
++ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
++ return ret_val;
++}
++
++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
++{
++ int old_chunk;
++ int ret_val = YAFFS_OK;
++ int i;
++ int is_checkpt_block;
++ int max_copies;
++ int chunks_before = yaffs_get_erased_chunks(dev);
++ int chunks_after;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
++
++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d, in use %d, shrink %d, whole_block %d",
++ block, bi->pages_in_use, bi->has_shrink_hdr,
++ whole_block);
++
++ /*yaffs_verify_free_chunks(dev); */
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
++
++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
++
++ dev->gc_disable = 1;
++
++ yaffs_summary_gc(dev, block);
++
++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d that has no chunks in use",
++ block);
++ yaffs_block_became_dirty(dev, block);
++ } else {
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_verify_blk(dev, bi, block);
++
++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
++
++ for (/* init already done */ ;
++ ret_val == YAFFS_OK &&
++ dev->gc_chunk < dev->param.chunks_per_block &&
++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
++ max_copies > 0;
++ dev->gc_chunk++, old_chunk++) {
++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
++ /* Page is in use and might need to be copied */
++ max_copies--;
++ ret_val = yaffs_gc_process_chunk(dev, bi,
++ old_chunk, buffer);
++ }
++ }
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ yaffs_verify_collected_blk(dev, bi, block);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ /*
++ * The gc did not complete. Set block state back to FULL
++ * because checkpointing does not restore gc.
++ */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ } else {
++ /* The gc completed. */
++ /* Do any required cleanups */
++ for (i = 0; i < dev->n_clean_ups; i++) {
++ /* Time to delete the file too */
++ struct yaffs_obj *object =
++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
++ if (object) {
++ yaffs_free_tnode(dev,
++ object->variant.file_variant.top);
++ object->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: About to finally delete object %d",
++ object->obj_id);
++ yaffs_generic_obj_del(object);
++ object->my_dev->n_deleted_files--;
++ }
++
++ }
++ chunks_after = yaffs_get_erased_chunks(dev);
++ if (chunks_before >= chunks_after)
++ yaffs_trace(YAFFS_TRACE_GC,
++ "gc did not increase free chunks before %d after %d",
++ chunks_before, chunks_after);
++ dev->gc_block = 0;
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ dev->gc_disable = 0;
++
++ return ret_val;
++}
++
++/*
++ * find_gc_block() selects the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
++ int aggressive, int background)
++{
++ int i;
++ int iterations;
++ unsigned selected = 0;
++ int prioritised = 0;
++ int prioritised_exist = 0;
++ struct yaffs_block_info *bi;
++ int threshold;
++
++ /* First let's see if we need to grab a prioritised block */
++ if (dev->has_pending_prioritised_gc && !aggressive) {
++ dev->gc_dirtiest = 0;
++ bi = dev->block_info;
++ for (i = dev->internal_start_block;
++ i <= dev->internal_end_block && !selected; i++) {
++
++ if (bi->gc_prioritise) {
++ prioritised_exist = 1;
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ selected = i;
++ prioritised = 1;
++ }
++ }
++ bi++;
++ }
++
++ /*
++ * If there is a prioritised block and none was selected then
++ * this happened because there is at least one old dirty block
++ * gumming up the works. Let's gc the oldest dirty block.
++ */
++
++ if (prioritised_exist &&
++ !selected && dev->oldest_dirty_block > 0)
++ selected = dev->oldest_dirty_block;
++
++ if (!prioritised_exist) /* None found, so we can clear this */
++ dev->has_pending_prioritised_gc = 0;
++ }
++
++ /* If we're doing aggressive GC then we are happy to take a less-dirty
++ * block, and search harder.
++ * else (leasurely gc), then we only bother to do this if the
++ * block has only a few pages in use.
++ */
++
++ if (!selected) {
++ int pages_used;
++ int n_blocks =
++ dev->internal_end_block - dev->internal_start_block + 1;
++ if (aggressive) {
++ threshold = dev->param.chunks_per_block;
++ iterations = n_blocks;
++ } else {
++ int max_threshold;
++
++ if (background)
++ max_threshold = dev->param.chunks_per_block / 2;
++ else
++ max_threshold = dev->param.chunks_per_block / 8;
++
++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++
++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++ if (threshold > max_threshold)
++ threshold = max_threshold;
++
++ iterations = n_blocks / 16 + 1;
++ if (iterations > 100)
++ iterations = 100;
++ }
++
++ for (i = 0;
++ i < iterations &&
++ (dev->gc_dirtiest < 1 ||
++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
++ i++) {
++ dev->gc_block_finder++;
++ if (dev->gc_block_finder < dev->internal_start_block ||
++ dev->gc_block_finder > dev->internal_end_block)
++ dev->gc_block_finder =
++ dev->internal_start_block;
++
++ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
++
++ pages_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ pages_used < dev->param.chunks_per_block &&
++ (dev->gc_dirtiest < 1 ||
++ pages_used < dev->gc_pages_in_use) &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ dev->gc_dirtiest = dev->gc_block_finder;
++ dev->gc_pages_in_use = pages_used;
++ }
++ }
++
++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
++ selected = dev->gc_dirtiest;
++ }
++
++ /*
++ * If nothing has been selected for a while, try the oldest dirty
++ * because that's gumming up the works.
++ */
++
++ if (!selected && dev->param.is_yaffs2 &&
++ dev->gc_not_done >= (background ? 10 : 20)) {
++ yaffs2_find_oldest_dirty_seq(dev);
++ if (dev->oldest_dirty_block > 0) {
++ selected = dev->oldest_dirty_block;
++ dev->gc_dirtiest = selected;
++ dev->oldest_dirty_gc_count++;
++ bi = yaffs_get_block_info(dev, selected);
++ dev->gc_pages_in_use =
++ bi->pages_in_use - bi->soft_del_pages;
++ } else {
++ dev->gc_not_done = 0;
++ }
++ }
++
++ if (selected) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC Selected block %d with %d free, prioritised:%d",
++ selected,
++ dev->param.chunks_per_block - dev->gc_pages_in_use,
++ prioritised);
++
++ dev->n_gc_blocks++;
++ if (background)
++ dev->bg_gcs++;
++
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ dev->gc_not_done = 0;
++ if (dev->refresh_skip > 0)
++ dev->refresh_skip--;
++ } else {
++ dev->gc_not_done++;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
++ dev->gc_block_finder, dev->gc_not_done, threshold,
++ dev->gc_dirtiest, dev->gc_pages_in_use,
++ dev->oldest_dirty_block, background ? " bg" : "");
++ }
++
++ return selected;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_check_gc(struct yaffs_dev *dev, int background)
++{
++ int aggressive = 0;
++ int gc_ok = YAFFS_OK;
++ int max_tries = 0;
++ int min_erased;
++ int erased_chunks;
++ int checkpt_block_adjust;
++
++ if (dev->param.gc_control_fn &&
++ (dev->param.gc_control_fn(dev) & 1) == 0)
++ return YAFFS_OK;
++
++ if (dev->gc_disable)
++ /* Bail out so we don't get recursive gc */
++ return YAFFS_OK;
++
++ /* This loop should pass the first time.
++ * Only loops here if the collection does not increase space.
++ */
++
++ do {
++ max_tries++;
++
++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
++
++ min_erased =
++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
++ erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ /* If we need a block soon then do aggressive gc. */
++ if (dev->n_erased_blocks < min_erased)
++ aggressive = 1;
++ else {
++ if (!background
++ && erased_chunks > (dev->n_free_chunks / 4))
++ break;
++
++ if (dev->gc_skip > 20)
++ dev->gc_skip = 20;
++ if (erased_chunks < dev->n_free_chunks / 2 ||
++ dev->gc_skip < 1 || background)
++ aggressive = 0;
++ else {
++ dev->gc_skip--;
++ break;
++ }
++ }
++
++ dev->gc_skip = 5;
++
++ /* If we don't already have a block being gc'd then see if we
++ * should start another */
++
++ if (dev->gc_block < 1 && !aggressive) {
++ dev->gc_block = yaffs2_find_refresh_block(dev);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++ if (dev->gc_block < 1) {
++ dev->gc_block =
++ yaffs_find_gc_block(dev, aggressive, background);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ if (dev->gc_block > 0) {
++ dev->all_gcs++;
++ if (!aggressive)
++ dev->passive_gc_count++;
++
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC n_erased_blocks %d aggressive %d",
++ dev->n_erased_blocks, aggressive);
++
++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
++ }
++
++ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
++ dev->gc_block > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
++ dev->n_erased_blocks, max_tries,
++ dev->gc_block);
++ }
++ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
++ (dev->gc_block > 0) && (max_tries < 2));
++
++ return aggressive ? gc_ok : YAFFS_OK;
++}
++
++/*
++ * yaffs_bg_gc()
++ * Garbage collects. Intended to be called from a background thread.
++ * Returns non-zero if at least half the free chunks are erased.
++ */
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
++{
++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
++
++ yaffs_check_gc(dev, 1);
++ return erased_chunks > dev->n_free_chunks / 2;
++}
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
++{
++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
++
++ if (nand_chunk >= 0)
++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
++ buffer, NULL);
++ else {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not found zero instead",
++ nand_chunk);
++ /* get sane (zero) data if you read a hole */
++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
++ return 0;
++ }
++
++}
++
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn)
++{
++ int block;
++ int page;
++ struct yaffs_ext_tags tags;
++ struct yaffs_block_info *bi;
++
++ if (chunk_id <= 0)
++ return;
++
++ dev->n_deletions++;
++ block = chunk_id / dev->param.chunks_per_block;
++ page = chunk_id % dev->param.chunks_per_block;
++
++ if (!yaffs_check_chunk_bit(dev, block, page))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Deleting invalid chunk %d", chunk_id);
++
++ bi = yaffs_get_block_info(dev, block);
++
++ yaffs2_update_oldest_dirty_seq(dev, block, bi);
++
++ yaffs_trace(YAFFS_TRACE_DELETION,
++ "line %d delete of chunk %d",
++ lyn, chunk_id);
++
++ if (!dev->param.is_yaffs2 && mark_flash &&
++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
++
++ memset(&tags, 0, sizeof(tags));
++ tags.is_deleted = 1;
++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
++ yaffs_handle_chunk_update(dev, chunk_id, &tags);
++ } else {
++ dev->n_unmarked_deletions++;
++ }
++
++ /* Pull out of the management area.
++ * If the whole block became dirty, this will kick off an erasure.
++ */
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
++ bi->block_state == YAFFS_BLOCK_STATE_FULL ||
++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->n_free_chunks++;
++ yaffs_clear_chunk_bit(dev, block, page);
++ bi->pages_in_use--;
++
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ yaffs_block_became_dirty(dev, block);
++ }
++ }
++}
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve)
++{
++ /* Find old chunk Need to do this to get serial number
++ * Write new one and patch into tree.
++ * Invalidate old tags.
++ */
++
++ int prev_chunk_id;
++ struct yaffs_ext_tags prev_tags;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_dev *dev = in->my_dev;
++
++ yaffs_check_gc(dev, 0);
++
++ /* Get the previous chunk at this location in the file if it exists.
++ * If it does not exist then put a zero into the tree. This creates
++ * the tnode now, rather than later when it is harder to clean up.
++ */
++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
++ if (prev_chunk_id < 1 &&
++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
++ return 0;
++
++ /* Set up new tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++
++ new_tags.chunk_id = inode_chunk;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number =
++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
++ new_tags.n_bytes = n_bytes;
++
++ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Writing %d bytes to chunk!!!!!!!!!",
++ n_bytes);
++ BUG();
++ }
++
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
++
++ if (new_chunk_id > 0) {
++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ yaffs_verify_file_sane(in);
++ }
++ return new_chunk_id;
++
++}
++
++
++
++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
++ const YCHAR *name, const void *value, int size,
++ int flags)
++{
++ struct yaffs_xattr_mod xmod;
++ int result;
++
++ xmod.set = set;
++ xmod.name = name;
++ xmod.data = value;
++ xmod.size = size;
++ xmod.flags = flags;
++ xmod.result = -ENOSPC;
++
++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
++
++ if (result > 0)
++ return xmod.result;
++ else
++ return -ENOSPC;
++}
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++ struct yaffs_xattr_mod *xmod)
++{
++ int retval = 0;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer = buffer + x_offs;
++
++ if (xmod->set)
++ retval =
++ nval_set(x_buffer, x_size, xmod->name, xmod->data,
++ xmod->size, xmod->flags);
++ else
++ retval = nval_del(x_buffer, x_size, xmod->name);
++
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ xmod->result = retval;
++
++ return retval;
++}
++
++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
++ void *value, int size)
++{
++ char *buffer = NULL;
++ int result;
++ struct yaffs_ext_tags tags;
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer;
++ int retval = 0;
++
++ if (obj->hdr_chunk < 1)
++ return -ENODATA;
++
++ /* If we know that the object has no xattribs then don't do all the
++ * reading and parsing.
++ */
++ if (obj->xattr_known && !obj->has_xattr) {
++ if (name)
++ return -ENODATA;
++ else
++ return 0;
++ }
++
++ buffer = (char *)yaffs_get_temp_buffer(dev);
++ if (!buffer)
++ return -ENOMEM;
++
++ result =
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
++
++ if (result != YAFFS_OK)
++ retval = -ENOENT;
++ else {
++ x_buffer = buffer + x_offs;
++
++ if (!obj->xattr_known) {
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ }
++
++ if (name)
++ retval = nval_get(x_buffer, x_size, name, value, size);
++ else
++ retval = nval_list(x_buffer, x_size, value, size);
++ }
++ yaffs_release_temp_buffer(dev, (u8 *) buffer);
++ return retval;
++}
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++ const void *value, int size, int flags)
++{
++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
++}
++
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
++{
++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
++}
++
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++ int size)
++{
++ return yaffs_do_xattrib_fetch(obj, name, value, size);
++}
++
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
++{
++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
++}
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
++{
++ u8 *buf;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++
++ if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
++ return;
++
++ dev = in->my_dev;
++ in->lazy_loaded = 0;
++ buf = yaffs_get_temp_buffer(dev);
++
++ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
++ oh = (struct yaffs_obj_hdr *)buf;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ yaffs_set_obj_name_from_oh(in, oh);
++
++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ in->variant.symlink_variant.alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.symlink_variant.alias)
++ alloc_failed = 1; /* Not returned */
++ }
++ yaffs_release_temp_buffer(dev, buf);
++}
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
++ const YCHAR *oh_name, int buff_size)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ if (dev->param.auto_unicode) {
++ if (*oh_name) {
++ /* It is an ASCII name, do an ASCII to
++ * unicode conversion */
++ const char *ascii_oh_name = (const char *)oh_name;
++ int n = buff_size - 1;
++ while (n > 0 && *ascii_oh_name) {
++ *name = *ascii_oh_name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ strncpy(name, oh_name + 1, buff_size - 1);
++ }
++ } else {
++#else
++ (void) dev;
++ {
++#endif
++ strncpy(name, oh_name, buff_size - 1);
++ }
++}
++
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
++ const YCHAR *name)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++
++ int is_ascii;
++ YCHAR *w;
++
++ if (dev->param.auto_unicode) {
++
++ is_ascii = 1;
++ w = name;
++
++ /* Figure out if the name will fit in ascii character set */
++ while (is_ascii && *w) {
++ if ((*w) & 0xff00)
++ is_ascii = 0;
++ w++;
++ }
++
++ if (is_ascii) {
++ /* It is an ASCII name, so convert unicode to ascii */
++ char *ascii_oh_name = (char *)oh_name;
++ int n = YAFFS_MAX_NAME_LENGTH - 1;
++ while (n > 0 && *name) {
++ *ascii_oh_name = *name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ /* Unicode name, so save starting at the second YCHAR */
++ *oh_name = 0;
++ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
++ }
++ } else {
++#else
++ dev = dev;
++ {
++#endif
++ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
++ }
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
++{
++
++ struct yaffs_block_info *bi;
++ struct yaffs_dev *dev = in->my_dev;
++ int prev_chunk_id;
++ int ret_val = 0;
++ int result = 0;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_ext_tags old_tags;
++ const YCHAR *alias = NULL;
++ u8 *buffer = NULL;
++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj_hdr *oh = NULL;
++ loff_t file_size = 0;
++
++ strcpy(old_name, _Y("silly old name"));
++
++ if (in->fake && in != dev->root_dir && !force && !xmod)
++ return ret_val;
++
++ yaffs_check_gc(dev, 0);
++ yaffs_check_obj_details_loaded(in);
++
++ buffer = yaffs_get_temp_buffer(in->my_dev);
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ prev_chunk_id = in->hdr_chunk;
++
++ if (prev_chunk_id > 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
++ buffer, &old_tags);
++
++ yaffs_verify_oh(in, oh, &old_tags, 0);
++ memcpy(old_name, oh->name, sizeof(oh->name));
++ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
++ } else {
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ }
++
++ oh->type = in->variant_type;
++ oh->yst_mode = in->yst_mode;
++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
++
++ yaffs_load_attribs_oh(oh, in);
++
++ if (in->parent)
++ oh->parent_obj_id = in->parent->obj_id;
++ else
++ oh->parent_obj_id = 0;
++
++ if (name && *name) {
++ memset(oh->name, 0, sizeof(oh->name));
++ yaffs_load_oh_from_name(dev, oh->name, name);
++ } else if (prev_chunk_id > 0) {
++ memcpy(oh->name, old_name, sizeof(oh->name));
++ } else {
++ memset(oh->name, 0, sizeof(oh->name));
++ }
++
++ oh->is_shrink = is_shrink;
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Should not happen */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
++ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
++ file_size = in->variant.file_variant.file_size;
++ yaffs_oh_size_load(oh, file_size);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = in->variant.symlink_variant.alias;
++ if (!alias)
++ alias = _Y("no alias");
++ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++ break;
++ }
++
++ /* process any xattrib modifications */
++ if (xmod)
++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
++
++ /* Tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++ in->serial++;
++ new_tags.chunk_id = 0;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number = in->serial;
++
++ /* Add extra info for file header */
++ new_tags.extra_available = 1;
++ new_tags.extra_parent_id = oh->parent_obj_id;
++ new_tags.extra_file_size = file_size;
++ new_tags.extra_is_shrink = oh->is_shrink;
++ new_tags.extra_equiv_id = oh->equiv_id;
++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
++ new_tags.extra_obj_type = in->variant_type;
++ yaffs_verify_oh(in, oh, &new_tags, 1);
++
++ /* Create new chunk in NAND */
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags,
++ (prev_chunk_id > 0) ? 1 : 0);
++
++ if (buffer)
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (new_chunk_id < 0)
++ return new_chunk_id;
++
++ in->hdr_chunk = new_chunk_id;
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ if (!yaffs_obj_cache_dirty(in))
++ in->dirty = 0;
++
++ /* If this was a shrink, then mark the block
++ * that the chunk lives on */
++ if (is_shrink) {
++ bi = yaffs_get_block_info(in->my_dev,
++ new_chunk_id /
++ in->my_dev->param.chunks_per_block);
++ bi->has_shrink_hdr = 1;
++ }
++
++
++ return new_chunk_id;
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
++{
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ struct yaffs_cache *cache;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++ if ((start + n) < dev->data_bytes_per_chunk)
++ n_copy = n;
++ else
++ n_copy = dev->data_bytes_per_chunk - start;
++
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ /* If the chunk is already in the cache or it is less than
++ * a whole chunk or we're using inband tags then use the cache
++ * (if there is caching) else bypass the cache.
++ */
++ if (cache || n_copy != dev->data_bytes_per_chunk ||
++ dev->param.inband_tags) {
++ if (dev->param.n_caches > 0) {
++
++ /* If we can't find the data in the cache,
++ * then load it up. */
++
++ if (!cache) {
++ cache =
++ yaffs_grab_chunk_cache(in->my_dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ cache->n_bytes = 0;
++ }
++
++ yaffs_use_cache(dev, cache, 0);
++
++ cache->locked = 1;
++
++ memcpy(buffer, &cache->data[start], n_copy);
++
++ cache->locked = 0;
++ } else {
++ /* Read into the local buffer then copy.. */
++
++ u8 *local_buffer =
++ yaffs_get_temp_buffer(dev);
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++
++ memcpy(buffer, &local_buffer[start], n_copy);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Read directly into the buffer. */
++ yaffs_rd_data_obj(in, chunk, buffer);
++ }
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ return n_done;
++}
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ int n_writeback;
++ loff_t start_write = offset;
++ int chunk_written = 0;
++ u32 n_bytes_read;
++ loff_t chunk_start;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0 && chunk_written >= 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++
++ if (((loff_t)chunk) *
++ dev->data_bytes_per_chunk + start != offset ||
++ start >= dev->data_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "AddrToChunk of offset %lld gives chunk %d start %d",
++ offset, chunk, start);
++ }
++ chunk++; /* File pos to chunk in file offset */
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++
++ if ((start + n) < dev->data_bytes_per_chunk) {
++ n_copy = n;
++
++ /* Now calculate how many bytes to write back....
++ * If we're overwriting and not writing to then end of
++ * file then we need to write back as much as was there
++ * before.
++ */
++
++ chunk_start = (((loff_t)(chunk - 1)) *
++ dev->data_bytes_per_chunk);
++
++ if (chunk_start > in->variant.file_variant.file_size)
++ n_bytes_read = 0; /* Past end of file */
++ else
++ n_bytes_read =
++ in->variant.file_variant.file_size -
++ chunk_start;
++
++ if (n_bytes_read > dev->data_bytes_per_chunk)
++ n_bytes_read = dev->data_bytes_per_chunk;
++
++ n_writeback =
++ (n_bytes_read >
++ (start + n)) ? n_bytes_read : (start + n);
++
++ if (n_writeback < 0 ||
++ n_writeback > dev->data_bytes_per_chunk)
++ BUG();
++
++ } else {
++ n_copy = dev->data_bytes_per_chunk - start;
++ n_writeback = dev->data_bytes_per_chunk;
++ }
++
++ if (n_copy != dev->data_bytes_per_chunk ||
++ !dev->param.cache_bypass_aligned ||
++ dev->param.inband_tags) {
++ /* An incomplete start or end chunk (or maybe both
++ * start and end chunk), or we're using inband tags,
++ * or we're forcing writes through the cache,
++ * so we want to use the cache buffers.
++ */
++ if (dev->param.n_caches > 0) {
++ struct yaffs_cache *cache;
++
++ /* If we can't find the data in the cache, then
++ * load the cache */
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ if (!cache &&
++ yaffs_check_alloc_available(dev, 1)) {
++ cache = yaffs_grab_chunk_cache(dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ } else if (cache &&
++ !cache->dirty &&
++ !yaffs_check_alloc_available(dev,
++ 1)) {
++ /* Drop the cache if it was a read cache
++ * item and no space check has been made
++ * for it.
++ */
++ cache = NULL;
++ }
++
++ if (cache) {
++ yaffs_use_cache(dev, cache, 1);
++ cache->locked = 1;
++
++ memcpy(&cache->data[start], buffer,
++ n_copy);
++
++ cache->locked = 0;
++ cache->n_bytes = n_writeback;
++
++ if (write_through) {
++ chunk_written =
++ yaffs_wr_data_obj
++ (cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ }
++ } else {
++ chunk_written = -1; /* fail write */
++ }
++ } else {
++ /* An incomplete start or end chunk (or maybe
++ * both start and end chunk). Read into the
++ * local buffer then copy over and write back.
++ */
++
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++ memcpy(&local_buffer[start], buffer, n_copy);
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk,
++ local_buffer,
++ n_writeback, 0);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Write directly from the buffer. */
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk, buffer,
++ dev->data_bytes_per_chunk, 0);
++
++ /* Since we've overwritten the cached data,
++ * we better invalidate it. */
++ yaffs_invalidate_chunk_cache(in, chunk);
++ }
++
++ if (chunk_written >= 0) {
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ }
++
++ /* Update file object */
++
++ if ((start_write + n_done) > in->variant.file_variant.file_size)
++ in->variant.file_variant.file_size = (start_write + n_done);
++
++ in->dirty = 1;
++ return n_done;
++}
++
++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++ yaffs2_handle_hole(in, offset);
++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
++}
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
++{
++
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++ int i;
++ int chunk_id;
++ u32 dummy;
++ int last_del;
++ int start_del;
++
++ if (old_size > 0)
++ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
++ else
++ last_del = 0;
++
++ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
++ &start_del, &dummy);
++ last_del++;
++ start_del++;
++
++ /* Delete backwards so that we don't end up with holes if
++ * power is lost part-way through the operation.
++ */
++ for (i = last_del; i >= start_del; i--) {
++ /* NB this could be optimised somewhat,
++ * eg. could retrieve the tags and write them without
++ * using yaffs_chunk_del
++ */
++
++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
++
++ if (chunk_id < 1)
++ continue;
++
++ if (chunk_id <
++ (dev->internal_start_block * dev->param.chunks_per_block) ||
++ chunk_id >=
++ ((dev->internal_end_block + 1) *
++ dev->param.chunks_per_block)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Found daft chunk_id %d for %d",
++ chunk_id, i);
++ } else {
++ in->n_data_chunks--;
++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
++ }
++ }
++}
++
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
++{
++ int new_full;
++ u32 new_partial;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
++
++ yaffs_prune_chunks(obj, new_size);
++
++ if (new_partial != 0) {
++ int last_chunk = 1 + new_full;
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ /* Rewrite the last chunk with its new size and zero pad */
++ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
++ memset(local_buffer + new_partial, 0,
++ dev->data_bytes_per_chunk - new_partial);
++
++ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
++ new_partial, 1);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++
++ obj->variant.file_variant.file_size = new_size;
++
++ yaffs_prune_tree(dev, &obj->variant.file_variant);
++}
++
++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
++{
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++
++ yaffs_flush_file_cache(in);
++ yaffs_invalidate_whole_cache(in);
++
++ yaffs_check_gc(dev, 0);
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ if (new_size == old_size)
++ return YAFFS_OK;
++
++ if (new_size > old_size) {
++ yaffs2_handle_hole(in, new_size);
++ in->variant.file_variant.file_size = new_size;
++ } else {
++ /* new_size < old_size */
++ yaffs_resize_file_down(in, new_size);
++ }
++
++ /* Write a new object header to reflect the resize.
++ * show we've shrunk the file, if need be
++ * Do this only if the file is not in the deleted directories
++ * and is not shadowed.
++ */
++ if (in->parent &&
++ !in->is_shadowed &&
++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ in->parent->obj_id != YAFFS_OBJECTID_DELETED)
++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
++
++ return YAFFS_OK;
++}
++
++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
++{
++ if (!in->dirty)
++ return YAFFS_OK;
++
++ yaffs_flush_file_cache(in);
++
++ if (data_sync)
++ return YAFFS_OK;
++
++ if (update_time)
++ yaffs_load_current_time(in, 0, 0);
++
++ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
++ YAFFS_OK : YAFFS_FAIL;
++}
++
++
++/* yaffs_del_file deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
++{
++ int ret_val;
++ int del_now = 0;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!in->my_inode)
++ del_now = 1;
++
++ if (del_now) {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->del_dir,
++ _Y("deleted"), 0, 0);
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: immediate deletion of file %d",
++ in->obj_id);
++ in->deleted = 1;
++ in->my_dev->n_deleted_files++;
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++ yaffs_soft_del_file(in);
++ } else {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++ return ret_val;
++}
++
++static int yaffs_del_file(struct yaffs_obj *in)
++{
++ int ret_val = YAFFS_OK;
++ int deleted; /* Need to cache value on stack if in is freed */
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++
++ if (in->n_data_chunks > 0) {
++ /* Use soft deletion if there is data in the file.
++ * That won't be the case if it has been resized to zero.
++ */
++ if (!in->unlinked)
++ ret_val = yaffs_unlink_file_if_needed(in);
++
++ deleted = in->deleted;
++
++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
++ in->deleted = 1;
++ deleted = 1;
++ in->my_dev->n_deleted_files++;
++ yaffs_soft_del_file(in);
++ }
++ return deleted ? YAFFS_OK : YAFFS_FAIL;
++ } else {
++ /* The file has no data chunks so we toss it immediately */
++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
++ in->variant.file_variant.top = NULL;
++ yaffs_generic_obj_del(in);
++
++ return YAFFS_OK;
++ }
++}
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
++{
++ return (obj &&
++ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++ !(list_empty(&obj->variant.dir_variant.children));
++}
++
++static int yaffs_del_dir(struct yaffs_obj *obj)
++{
++ /* First check that the directory is empty. */
++ if (yaffs_is_non_empty_dir(obj))
++ return YAFFS_FAIL;
++
++ return yaffs_generic_obj_del(obj);
++}
++
++static int yaffs_del_symlink(struct yaffs_obj *in)
++{
++ kfree(in->variant.symlink_variant.alias);
++ in->variant.symlink_variant.alias = NULL;
++
++ return yaffs_generic_obj_del(in);
++}
++
++static int yaffs_del_link(struct yaffs_obj *in)
++{
++ /* remove this hardlink from the list associated with the equivalent
++ * object
++ */
++ list_del_init(&in->hard_links);
++ return yaffs_generic_obj_del(in);
++}
++
++int yaffs_del_obj(struct yaffs_obj *obj)
++{
++ int ret_val = -1;
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ ret_val = yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!list_empty(&obj->variant.dir_variant.dirty)) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Remove object %d from dirty directories",
++ obj->obj_id);
++ list_del_init(&obj->variant.dir_variant.dirty);
++ }
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ ret_val = yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ ret_val = yaffs_del_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ ret_val = yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ ret_val = 0;
++ break; /* should not happen. */
++ }
++ return ret_val;
++}
++
++
++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
++ struct yaffs_obj *to_dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_add_obj_to_dir(to_dir, obj);
++ }
++}
++
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type)
++{
++ /* Tear down the old variant */
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ /* Nuke file data */
++ yaffs_resize_file(obj, 0);
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Put the children in lost and found. */
++ yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
++ if (!list_empty(&obj->variant.dir_variant.dirty))
++ list_del_init(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ /* Nuke symplink data */
++ kfree(obj->variant.symlink_variant.alias);
++ obj->variant.symlink_variant.alias = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ list_del_init(&obj->hard_links);
++ break;
++ default:
++ break;
++ }
++
++ memset(&obj->variant, 0, sizeof(obj->variant));
++
++ /*Set up new variant if the memset is not enough. */
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ default:
++ break;
++ }
++
++ obj->variant_type = type;
++
++ return obj;
++
++}
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj)
++{
++ int del_now = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (!obj->my_inode)
++ del_now = 1;
++
++ yaffs_update_parent(obj->parent);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ return yaffs_del_link(obj);
++ } else if (!list_empty(&obj->hard_links)) {
++ /* Curve ball: We're unlinking an object that has a hardlink.
++ *
++ * This problem arises because we are not strictly following
++ * The Linux link/inode model.
++ *
++ * We can't really delete the object.
++ * Instead, we do the following:
++ * - Select a hardlink.
++ * - Unhook it from the hard links
++ * - Move it from its parent directory so that the rename works.
++ * - Rename the object to the hardlink's name.
++ * - Delete the hardlink
++ */
++
++ struct yaffs_obj *hl;
++ struct yaffs_obj *parent;
++ int ret_val;
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
++ hard_links);
++
++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++ parent = hl->parent;
++
++ list_del_init(&hl->hard_links);
++
++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
++
++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
++
++ if (ret_val == YAFFS_OK)
++ ret_val = yaffs_generic_obj_del(hl);
++
++ return ret_val;
++
++ } else if (del_now) {
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ list_del_init(&obj->variant.dir_variant.dirty);
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ return yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ return YAFFS_FAIL;
++ }
++ } else if (yaffs_is_non_empty_dir(obj)) {
++ return YAFFS_FAIL;
++ } else {
++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++}
++
++static int yaffs_unlink_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->unlink_allowed)
++ return yaffs_unlink_worker(obj);
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
++{
++ struct yaffs_obj *obj;
++
++ obj = yaffs_find_by_name(dir, name);
++ return yaffs_unlink_obj(obj);
++}
++
++/* Note:
++ * If old_name is NULL then we take old_dir as the object to be renamed.
++ */
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
++ struct yaffs_obj *new_dir, const YCHAR *new_name)
++{
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *existing_target = NULL;
++ int force = 0;
++ int result;
++ struct yaffs_dev *dev;
++
++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ dev = old_dir->my_dev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ /* Special case for case insemsitive systems.
++ * While look-up is case insensitive, the name isn't.
++ * Therefore we might want to change x.txt to X.txt
++ */
++ if (old_dir == new_dir &&
++ old_name && new_name &&
++ strcmp(old_name, new_name) == 0)
++ force = 1;
++#endif
++
++ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ /* ENAMETOOLONG */
++ return YAFFS_FAIL;
++
++ if (old_name)
++ obj = yaffs_find_by_name(old_dir, old_name);
++ else{
++ obj = old_dir;
++ old_dir = obj->parent;
++ }
++
++ if (obj && obj->rename_allowed) {
++ /* Now handle an existing target, if there is one */
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++ if (yaffs_is_non_empty_dir(existing_target)) {
++ return YAFFS_FAIL; /* ENOTEMPTY */
++ } else if (existing_target && existing_target != obj) {
++ /* Nuke the target first, using shadowing,
++ * but only if it isn't the same object.
++ *
++ * Note we must disable gc here otherwise it can mess
++ * up the shadowing.
++ *
++ */
++ dev->gc_disable = 1;
++ yaffs_change_obj_name(obj, new_dir, new_name, force,
++ existing_target->obj_id);
++ existing_target->is_shadowed = 1;
++ yaffs_unlink_obj(existing_target);
++ dev->gc_disable = 0;
++ }
++
++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
++
++ yaffs_update_parent(old_dir);
++ if (new_dir != old_dir)
++ yaffs_update_parent(new_dir);
++
++ return result;
++ }
++ return YAFFS_FAIL;
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning)
++{
++ struct yaffs_obj *obj;
++
++ if (backward_scanning) {
++ /* Handle YAFFS2 case (backward scanning)
++ * If the shadowed object exists then ignore.
++ */
++ obj = yaffs_find_by_number(dev, obj_id);
++ if (obj)
++ return;
++ }
++
++ /* Let's create it (if it does not exist) assuming it is a file so that
++ * it can do shrinking etc.
++ * We put it in unlinked dir to be cleaned up after the scanning
++ */
++ obj =
++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
++ if (!obj)
++ return;
++ obj->is_shadowed = 1;
++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
++ obj->variant.file_variant.shrink_size = 0;
++ obj->valid = 1; /* So that we don't read any other info. */
++}
++
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
++{
++ struct list_head *lh;
++ struct list_head *save;
++ struct yaffs_obj *hl;
++ struct yaffs_obj *in;
++
++ list_for_each_safe(lh, save, hard_list) {
++ hl = list_entry(lh, struct yaffs_obj, hard_links);
++ in = yaffs_find_by_number(dev,
++ hl->variant.hardlink_variant.equiv_id);
++
++ if (in) {
++ /* Add the hardlink pointers */
++ hl->variant.hardlink_variant.equiv_obj = in;
++ list_add(&hl->hard_links, &in->hard_links);
++ } else {
++ /* Todo Need to report/handle this better.
++ * Got a problem... hardlink to a non-existant object
++ */
++ hl->variant.hardlink_variant.equiv_obj = NULL;
++ INIT_LIST_HEAD(&hl->hard_links);
++ }
++ }
++}
++
++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
++{
++ /*
++ * Sort out state of unlinked and deleted objects after scanning.
++ */
++ struct list_head *i;
++ struct list_head *n;
++ struct yaffs_obj *l;
++
++ if (dev->read_only)
++ return;
++
++ /* Soft delete all the unlinked files */
++ list_for_each_safe(i, n,
++ &dev->unlinked_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++
++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ * This code assumes that we don't ever change the current relationships
++ * between directories:
++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
++ * lost-n-found->parent == root_dir
++ *
++ * This fixes the problem where directories might have inadvertently been
++ * deleted leaving the object "hanging" without being rooted in the
++ * directory tree.
++ */
++
++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++ return (obj == dev->del_dir ||
++ obj == dev->unlinked_dir || obj == dev->root_dir);
++}
++
++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_obj *parent;
++ int i;
++ struct list_head *lh;
++ struct list_head *n;
++ int depth_limit;
++ int hanging;
++
++ if (dev->read_only)
++ return;
++
++ /* Iterate through the objects in each hash entry,
++ * looking at each object.
++ * Make sure it is rooted.
++ */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ parent = obj->parent;
++
++ if (yaffs_has_null_parent(dev, obj)) {
++ /* These directories are not hanging */
++ hanging = 0;
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ hanging = 1;
++ } else if (yaffs_has_null_parent(dev, parent)) {
++ hanging = 0;
++ } else {
++ /*
++ * Need to follow the parent chain to
++ * see if it is hanging.
++ */
++ hanging = 0;
++ depth_limit = 100;
++
++ while (parent != dev->root_dir &&
++ parent->parent &&
++ parent->parent->variant_type ==
++ YAFFS_OBJECT_TYPE_DIRECTORY &&
++ depth_limit > 0) {
++ parent = parent->parent;
++ depth_limit--;
++ }
++ if (parent != dev->root_dir)
++ hanging = 1;
++ }
++ if (hanging) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Hanging object %d moved to lost and found",
++ obj->obj_id);
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++ }
++ }
++ }
++}
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_del_dir_contents(struct yaffs_obj *dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ BUG();
++
++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
++ yaffs_del_dir_contents(obj);
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Deleting lost_found object %d",
++ obj->obj_id);
++ yaffs_unlink_obj(obj);
++ }
++}
++
++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
++{
++ yaffs_del_dir_contents(dev->lost_n_found);
++}
++
++
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
++ const YCHAR *name)
++{
++ int sum;
++ struct list_head *i;
++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj *l;
++
++ if (!name)
++ return NULL;
++
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: null pointer directory"
++ );
++ BUG();
++ return NULL;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: non-directory"
++ );
++ BUG();
++ }
++
++ sum = yaffs_calc_name_sum(name);
++
++ list_for_each(i, &directory->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++
++ if (l->parent != directory)
++ BUG();
++
++ yaffs_check_obj_details_loaded(l);
++
++ /* Special case for lost-n-found */
++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
++ return l;
++ } else if (l->sum == sum || l->hdr_chunk <= 0) {
++ /* LostnFound chunk called Objxxx
++ * Do a real check
++ */
++ yaffs_get_obj_name(l, buffer,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
++ return l;
++ }
++ }
++ return NULL;
++}
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ obj = obj->variant.hardlink_variant.equiv_obj;
++ yaffs_check_obj_details_loaded(obj);
++ }
++ return obj;
++}
++
++/*
++ * A note or two on object names.
++ * * If the object name is missing, we then make one up in the form objnnn
++ *
++ * * ASCII names are stored in the object header's name field from byte zero
++ * * Unicode names are historically stored starting from byte zero.
++ *
++ * Then there are automatic Unicode names...
++ * The purpose of these is to save names in a way that can be read as
++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
++ * system to share files.
++ *
++ * These automatic unicode are stored slightly differently...
++ * - If the name can fit in the ASCII character space then they are saved as
++ * ascii names as per above.
++ * - If the name needs Unicode then the name is saved in Unicode
++ * starting at oh->name[1].
++
++ */
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size)
++{
++ /* Create an object name if we could not find one. */
++ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
++ YCHAR local_name[20];
++ YCHAR num_string[20];
++ YCHAR *x = &num_string[19];
++ unsigned v = obj->obj_id;
++ num_string[19] = 0;
++ while (v > 0) {
++ x--;
++ *x = '0' + (v % 10);
++ v /= 10;
++ }
++ /* make up a name */
++ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
++ strcat(local_name, x);
++ strncpy(name, local_name, buffer_size - 1);
++ }
++}
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
++{
++ memset(name, 0, buffer_size * sizeof(YCHAR));
++ yaffs_check_obj_details_loaded(obj);
++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
++ } else if (obj->short_name[0]) {
++ strcpy(name, obj->short_name);
++ } else if (obj->hdr_chunk > 0) {
++ int result;
++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
++
++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
++
++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
++
++ if (obj->hdr_chunk > 0) {
++ result = yaffs_rd_chunk_tags_nand(obj->my_dev,
++ obj->hdr_chunk,
++ buffer, NULL);
++ }
++ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
++ buffer_size);
++
++ yaffs_release_temp_buffer(obj->my_dev, buffer);
++ }
++
++ yaffs_fix_null_name(obj, name, buffer_size);
++
++ return strnlen(name, YAFFS_MAX_NAME_LENGTH);
++}
++
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
++{
++ /* Dereference any hard linking */
++ obj = yaffs_get_equivalent_obj(obj);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ return obj->variant.file_variant.file_size;
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ if (!obj->variant.symlink_variant.alias)
++ return 0;
++ return strnlen(obj->variant.symlink_variant.alias,
++ YAFFS_MAX_ALIAS_LENGTH);
++ } else {
++ /* Only a directory should drop through to here */
++ return obj->my_dev->data_bytes_per_chunk;
++ }
++}
++
++int yaffs_get_obj_link_count(struct yaffs_obj *obj)
++{
++ int count = 0;
++ struct list_head *i;
++
++ if (!obj->unlinked)
++ count++; /* the object itself */
++
++ list_for_each(i, &obj->hard_links)
++ count++; /* add the hard links; */
++
++ return count;
++}
++
++int yaffs_get_obj_inode(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ return obj->obj_id;
++}
++
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return DT_DIR;
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return DT_LNK;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ if (S_ISFIFO(obj->yst_mode))
++ return DT_FIFO;
++ if (S_ISCHR(obj->yst_mode))
++ return DT_CHR;
++ if (S_ISBLK(obj->yst_mode))
++ return DT_BLK;
++ if (S_ISSOCK(obj->yst_mode))
++ return DT_SOCK;
++ return DT_REG;
++ break;
++ default:
++ return DT_REG;
++ break;
++ }
++}
++
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
++ return yaffs_clone_str(obj->variant.symlink_variant.alias);
++ else
++ return yaffs_clone_str(_Y(""));
++}
++
++/*--------------------------- Initialisation code -------------------------- */
++
++static int yaffs_check_dev_fns(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++ struct yaffs_tags_handler *tagger = &dev->tagger;
++
++ /* Common functions, gotta have */
++ if (!drv->drv_read_chunk_fn ||
++ !drv->drv_write_chunk_fn ||
++ !drv->drv_erase_fn)
++ return 0;
++
++ if (dev->param.is_yaffs2 &&
++ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
++ return 0;
++
++ /* Install the default tags marshalling functions if needed. */
++ yaffs_tags_compat_install(dev);
++ yaffs_tags_marshall_install(dev);
++
++ /* Check we now have the marshalling functions required. */
++ if (!tagger->write_chunk_tags_fn ||
++ !tagger->read_chunk_tags_fn ||
++ !tagger->query_block_fn ||
++ !tagger->mark_bad_fn)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs_create_initial_dir(struct yaffs_dev *dev)
++{
++ /* Initialise the unlinked, deleted, root and lost+found directories */
++ dev->lost_n_found = dev->root_dir = NULL;
++ dev->unlinked_dir = dev->del_dir = NULL;
++ dev->unlinked_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++ dev->del_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++ dev->root_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
++ YAFFS_ROOT_MODE | S_IFDIR);
++ dev->lost_n_found =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
++ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
++ && dev->del_dir) {
++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++/* Low level init.
++ * Typically only used by yaffs_guts_initialise, but also used by the
++ * Low level yaffs driver tests.
++ */
++
++int yaffs_guts_ll_init(struct yaffs_dev *dev)
++{
++
++
++ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
++
++ if (!dev) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Need a device"
++ );
++ return YAFFS_FAIL;
++ }
++
++ if (dev->ll_init)
++ return YAFFS_OK;
++
++ dev->internal_start_block = dev->param.start_block;
++ dev->internal_end_block = dev->param.end_block;
++ dev->block_offset = 0;
++ dev->chunk_offset = 0;
++ dev->n_free_chunks = 0;
++
++ dev->gc_block = 0;
++
++ if (dev->param.start_block == 0) {
++ dev->internal_start_block = dev->param.start_block + 1;
++ dev->internal_end_block = dev->param.end_block + 1;
++ dev->block_offset = 1;
++ dev->chunk_offset = dev->param.chunks_per_block;
++ }
++
++ /* Check geometry parameters. */
++
++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 1024) ||
++ (!dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 512) ||
++ (dev->param.inband_tags && !dev->param.is_yaffs2) ||
++ dev->param.chunks_per_block < 2 ||
++ dev->param.n_reserved_blocks < 2 ||
++ dev->internal_start_block <= 0 ||
++ dev->internal_end_block <= 0 ||
++ dev->internal_end_block <=
++ (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
++ ) {
++ /* otherwise it is too small */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
++ dev->param.total_bytes_per_chunk,
++ dev->param.is_yaffs2 ? "2" : "",
++ dev->param.inband_tags);
++ return YAFFS_FAIL;
++ }
++
++ /* Sort out space for inband tags, if required */
++ if (dev->param.inband_tags)
++ dev->data_bytes_per_chunk =
++ dev->param.total_bytes_per_chunk -
++ sizeof(struct yaffs_packed_tags2_tags_only);
++ else
++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
++
++ /* Got the right mix of functions? */
++ if (!yaffs_check_dev_fns(dev)) {
++ /* Function missing */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "device function(s) missing or wrong");
++
++ return YAFFS_FAIL;
++ }
++
++ if (yaffs_init_nand(dev) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev)
++{
++ int i;
++ enum yaffs_block_state state;
++ u32 dummy;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if(dev->is_mounted)
++ return YAFFS_FAIL;
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ yaffs_query_init_block_state(dev, i, &state, &dummy);
++ if (state != YAFFS_BLOCK_STATE_DEAD)
++ yaffs_erase_block(dev, i);
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_initialise(struct yaffs_dev *dev)
++{
++ int init_failed = 0;
++ unsigned x;
++ int bits;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if (dev->is_mounted) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
++ return YAFFS_FAIL;
++ }
++
++ dev->is_mounted = 1;
++
++ /* OK now calculate a few things for the device */
++
++ /*
++ * Calculate all the chunk size manipulation numbers:
++ */
++ x = dev->data_bytes_per_chunk;
++ /* We always use dev->chunk_shift and dev->chunk_div */
++ dev->chunk_shift = calc_shifts(x);
++ x >>= dev->chunk_shift;
++ dev->chunk_div = x;
++ /* We only use chunk mask if chunk_div is 1 */
++ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
++
++ /*
++ * Calculate chunk_grp_bits.
++ * We need to find the next power of 2 > than internal_end_block
++ */
++
++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
++
++ bits = calc_shifts_ceiling(x);
++
++ /* Set up tnode width if wide tnodes are enabled. */
++ if (!dev->param.wide_tnodes_disabled) {
++ /* bits must be even so that we end up with 32-bit words */
++ if (bits & 1)
++ bits++;
++ if (bits < 16)
++ dev->tnode_width = 16;
++ else
++ dev->tnode_width = bits;
++ } else {
++ dev->tnode_width = 16;
++ }
++
++ dev->tnode_mask = (1 << dev->tnode_width) - 1;
++
++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++ * so if the bitwidth of the
++ * chunk range we're using is greater than 16 we need
++ * to figure out chunk shift and chunk_grp_size
++ */
++
++ if (bits <= dev->tnode_width)
++ dev->chunk_grp_bits = 0;
++ else
++ dev->chunk_grp_bits = bits - dev->tnode_width;
++
++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
++ if (dev->tnode_size < sizeof(struct yaffs_tnode))
++ dev->tnode_size = sizeof(struct yaffs_tnode);
++
++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
++
++ if (dev->param.chunks_per_block < dev->chunk_grp_size) {
++ /* We have a problem because the soft delete won't work if
++ * the chunk group size > chunks per block.
++ * This can be remedied by using larger "virtual blocks".
++ */
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
++
++ return YAFFS_FAIL;
++ }
++
++ /* Finished verifying the device, continue with initialisation */
++
++ /* More device initialisation */
++ dev->all_gcs = 0;
++ dev->passive_gc_count = 0;
++ dev->oldest_dirty_gc_count = 0;
++ dev->bg_gcs = 0;
++ dev->gc_block_finder = 0;
++ dev->buffered_block = -1;
++ dev->doing_buffered_block_rewrite = 0;
++ dev->n_deleted_files = 0;
++ dev->n_bg_deletions = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_ecc_fixed = 0;
++ dev->n_ecc_unfixed = 0;
++ dev->n_tags_ecc_fixed = 0;
++ dev->n_tags_ecc_unfixed = 0;
++ dev->n_erase_failures = 0;
++ dev->n_erased_blocks = 0;
++ dev->gc_disable = 0;
++ dev->has_pending_prioritised_gc = 1;
++ /* Assume the worst for now, will get fixed on first GC */
++ INIT_LIST_HEAD(&dev->dirty_dirs);
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++
++ /* Initialise temporary buffers and caches. */
++ if (!yaffs_init_tmp_buffers(dev))
++ init_failed = 1;
++
++ dev->cache = NULL;
++ dev->gc_cleanup_list = NULL;
++
++ if (!init_failed && dev->param.n_caches > 0) {
++ int i;
++ void *buf;
++ int cache_bytes =
++ dev->param.n_caches * sizeof(struct yaffs_cache);
++
++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
++
++ dev->cache = kmalloc(cache_bytes, GFP_NOFS);
++
++ buf = (u8 *) dev->cache;
++
++ if (dev->cache)
++ memset(dev->cache, 0, cache_bytes);
++
++ for (i = 0; i < dev->param.n_caches && buf; i++) {
++ dev->cache[i].object = NULL;
++ dev->cache[i].last_use = 0;
++ dev->cache[i].dirty = 0;
++ dev->cache[i].data = buf =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ }
++ if (!buf)
++ init_failed = 1;
++
++ dev->cache_last_use = 0;
++ }
++
++ dev->cache_hits = 0;
++
++ if (!init_failed) {
++ dev->gc_cleanup_list =
++ kmalloc(dev->param.chunks_per_block * sizeof(u32),
++ GFP_NOFS);
++ if (!dev->gc_cleanup_list)
++ init_failed = 1;
++ }
++
++ if (dev->param.is_yaffs2)
++ dev->param.use_header_file_size = 1;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && dev->param.is_yaffs2 &&
++ !dev->param.disable_summary &&
++ !yaffs_summary_init(dev))
++ init_failed = 1;
++
++ if (!init_failed) {
++ /* Now scan the flash. */
++ if (dev->param.is_yaffs2) {
++ if (yaffs2_checkpt_restore(dev)) {
++ yaffs_check_obj_details_loaded(dev->root_dir);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT |
++ YAFFS_TRACE_MOUNT,
++ "yaffs: restored from checkpoint"
++ );
++ } else {
++
++ /* Clean up the mess caused by an aborted
++ * checkpoint load then scan backwards.
++ */
++ yaffs_deinit_blocks(dev);
++
++ yaffs_deinit_tnodes_and_objs(dev);
++
++ dev->n_erased_blocks = 0;
++ dev->n_free_chunks = 0;
++ dev->alloc_block = -1;
++ dev->alloc_page = -1;
++ dev->n_deleted_files = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_bg_deletions = 0;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed
++ && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && !yaffs2_scan_backwards(dev))
++ init_failed = 1;
++ }
++ } else if (!yaffs1_scan(dev)) {
++ init_failed = 1;
++ }
++
++ yaffs_strip_deleted_objs(dev);
++ yaffs_fix_hanging_objs(dev);
++ if (dev->param.empty_lost_n_found)
++ yaffs_empty_l_n_f(dev);
++ }
++
++ if (init_failed) {
++ /* Clean up the mess */
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() aborted.");
++
++ yaffs_deinitialise(dev);
++ return YAFFS_FAIL;
++ }
++
++ /* Zero out stats */
++ dev->n_page_reads = 0;
++ dev->n_page_writes = 0;
++ dev->n_erasures = 0;
++ dev->n_gc_copies = 0;
++ dev->n_retried_writes = 0;
++
++ dev->n_retired_blocks = 0;
++
++ yaffs_verify_free_chunks(dev);
++ yaffs_verify_blocks(dev);
++
++ /* Clean up any aborted checkpoint data */
++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() done.");
++ return YAFFS_OK;
++}
++
++void yaffs_deinitialise(struct yaffs_dev *dev)
++{
++ if (dev->is_mounted) {
++ int i;
++
++ yaffs_deinit_blocks(dev);
++ yaffs_deinit_tnodes_and_objs(dev);
++ yaffs_summary_deinit(dev);
++
++ if (dev->param.n_caches > 0 && dev->cache) {
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ kfree(dev->cache[i].data);
++ dev->cache[i].data = NULL;
++ }
++
++ kfree(dev->cache);
++ dev->cache = NULL;
++ }
++
++ kfree(dev->gc_cleanup_list);
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ kfree(dev->temp_buffer[i].buffer);
++
++ dev->is_mounted = 0;
++
++ yaffs_deinit_nand(dev);
++ }
++}
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev)
++{
++ int n_free = 0;
++ int b;
++ struct yaffs_block_info *blk;
++
++ blk = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++ switch (blk->block_state) {
++ case YAFFS_BLOCK_STATE_EMPTY:
++ case YAFFS_BLOCK_STATE_ALLOCATING:
++ case YAFFS_BLOCK_STATE_COLLECTING:
++ case YAFFS_BLOCK_STATE_FULL:
++ n_free +=
++ (dev->param.chunks_per_block - blk->pages_in_use +
++ blk->soft_del_pages);
++ break;
++ default:
++ break;
++ }
++ blk++;
++ }
++ return n_free;
++}
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
++{
++ /* This is what we report to the outside world */
++ int n_free;
++ int n_dirty_caches;
++ int blocks_for_checkpt;
++ int i;
++
++ n_free = dev->n_free_chunks;
++ n_free += dev->n_deleted_files;
++
++ /* Now count and subtract the number of dirty chunks in the cache. */
++
++ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].dirty)
++ n_dirty_caches++;
++ }
++
++ n_free -= n_dirty_caches;
++
++ n_free -=
++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
++
++ /* Now figure checkpoint space and report that... */
++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
++
++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
++
++ if (n_free < 0)
++ n_free = 0;
++
++ return n_free;
++}
++
++
++
++/*
++ * Marshalling functions to get loff_t file sizes into and out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
++{
++ oh->file_size_low = (fsize & 0xFFFFFFFF);
++ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
++}
++
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
++{
++ loff_t retval;
++
++ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
++ retval = (((loff_t) oh->file_size_high) << 32) |
++ (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
++ else
++ retval = (loff_t) oh->file_size_low;
++
++ return retval;
++}
++
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
++{
++ int i;
++ struct yaffs_block_info *bi;
++ int s;
++
++ for(i = 0; i < 10; i++)
++ bs[i] = 0;
++
++ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ bi = yaffs_get_block_info(dev, i);
++ s = bi->block_state;
++ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
++ bs[0]++;
++ else
++ bs[s]++;
++ }
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_guts.h linux-3.10.40/fs/yaffs2/yaffs_guts.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_guts.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,1007 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "yportenv.h"
++
++#define YAFFS_OK 1
++#define YAFFS_FAIL 0
++
++/* Give us a Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xff
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC 0x5941ff53
++
++/*
++ * Tnodes form a tree with the tnodes in "levels"
++ * Levels greater than 0 hold 8 slots which point to other tnodes.
++ * Those at level 0 hold 16 slots which point to chunks in NAND.
++ *
++ * A maximum level of 8 thust supports files of size up to:
++ *
++ * 2^(3*MAX_LEVEL+4)
++ *
++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
++ * a maximum file size of around 512Gbytees with 2k chunks.
++ */
++#define YAFFS_NTNODES_LEVEL0 16
++#define YAFFS_TNODES_LEVEL0_BITS 4
++#define YAFFS_TNODES_LEVEL0_MASK 0xf
++
++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK 0x7
++#define YAFFS_TNODES_MAX_LEVEL 8
++#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
++ YAFFS_TNODES_INTERNAL_BITS * \
++ YAFFS_TNODES_MAX_LEVEL)
++#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
++
++#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
++
++/* Constants for YAFFS1 mode */
++#define YAFFS_BYTES_PER_SPARE 16
++#define YAFFS_BYTES_PER_CHUNK 512
++#define YAFFS_CHUNK_SIZE_SHIFT 9
++#define YAFFS_CHUNKS_PER_BLOCK 32
++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
++
++
++
++#define YAFFS_ALLOCATION_NOBJECTS 100
++#define YAFFS_ALLOCATION_NTNODES 100
++#define YAFFS_ALLOCATION_NLINKS 100
++
++#define YAFFS_NOBJECT_BUCKETS 256
++
++#define YAFFS_OBJECT_SPACE 0x40000
++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
++
++/* Binary data version stamps */
++#define YAFFS_SUMMARY_VERSION 1
++#define YAFFS_CHECKPOINT_VERSION 7
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH 127
++#define YAFFS_MAX_ALIAS_LENGTH 79
++#else
++#define YAFFS_MAX_NAME_LENGTH 255
++#define YAFFS_MAX_ALIAS_LENGTH 159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH 15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT 1
++#define YAFFS_OBJECTID_LOSTNFOUND 2
++#define YAFFS_OBJECTID_UNLINKED 3
++#define YAFFS_OBJECTID_DELETED 4
++
++/* Fake object Id for summary data */
++#define YAFFS_OBJECTID_SUMMARY 0x10
++
++/* Pseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
++
++#define YAFFS_MAX_SHORT_OP_CACHES 20
++
++#define YAFFS_N_TEMP_BUFFERS 6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS (5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
++
++/* ChunkCache is used for short read/write operations.*/
++struct yaffs_cache {
++ struct yaffs_obj *object;
++ int chunk_id;
++ int last_use;
++ int dirty;
++ int n_bytes; /* Only valid if the cache is dirty */
++ int locked; /* Can't push out or flush while locked. */
++ u8 *data;
++};
++
++/* yaffs1 tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
++ * otherwise the structure size will get blown out.
++ */
++
++struct yaffs_tags {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes_lsb:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 n_bytes_msb:2;
++};
++
++union yaffs_tags_union {
++ struct yaffs_tags as_tags;
++ u8 as_bytes[8];
++};
++
++
++/* Stuff used for extended tags in YAFFS2 */
++
++enum yaffs_ecc_result {
++ YAFFS_ECC_RESULT_UNKNOWN,
++ YAFFS_ECC_RESULT_NO_ERROR,
++ YAFFS_ECC_RESULT_FIXED,
++ YAFFS_ECC_RESULT_UNFIXED
++};
++
++enum yaffs_obj_type {
++ YAFFS_OBJECT_TYPE_UNKNOWN,
++ YAFFS_OBJECT_TYPE_FILE,
++ YAFFS_OBJECT_TYPE_SYMLINK,
++ YAFFS_OBJECT_TYPE_DIRECTORY,
++ YAFFS_OBJECT_TYPE_HARDLINK,
++ YAFFS_OBJECT_TYPE_SPECIAL
++};
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++struct yaffs_ext_tags {
++ unsigned chunk_used; /* Status of the chunk: used or unused */
++ unsigned obj_id; /* If 0 this is not used */
++ unsigned chunk_id; /* If 0 this is a header, else a data chunk */
++ unsigned n_bytes; /* Only valid for data chunks */
++
++ /* The following stuff only has meaning when we read */
++ enum yaffs_ecc_result ecc_result;
++ unsigned block_bad;
++
++ /* YAFFS 1 stuff */
++ unsigned is_deleted; /* The chunk is marked deleted */
++ unsigned serial_number; /* Yaffs1 2-bit serial number */
++
++ /* YAFFS2 stuff */
++ unsigned seq_number; /* The sequence number of this block */
++
++ /* Extra info if this is an object header (YAFFS2 only) */
++
++ unsigned extra_available; /* Extra info available if not zero */
++ unsigned extra_parent_id; /* The parent object */
++ unsigned extra_is_shrink; /* Is it a shrink header? */
++ unsigned extra_shadows; /* Does this shadow another object? */
++
++ enum yaffs_obj_type extra_obj_type; /* What object type? */
++
++ loff_t extra_file_size; /* Length if it is a file */
++ unsigned extra_equiv_id; /* Equivalent object for a hard link */
++};
++
++/* Spare structure for YAFFS1 */
++struct yaffs_spare {
++ u8 tb0;
++ u8 tb1;
++ u8 tb2;
++ u8 tb3;
++ u8 page_status; /* set to 0 to delete the chunk */
++ u8 block_status;
++ u8 tb4;
++ u8 tb5;
++ u8 ecc1[3];
++ u8 tb6;
++ u8 tb7;
++ u8 ecc2[3];
++};
++
++/*Special structure for passing through to mtd */
++struct yaffs_nand_spare {
++ struct yaffs_spare spare;
++ int eccres1;
++ int eccres2;
++};
++
++/* Block data in RAM */
++
++enum yaffs_block_state {
++ YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++ YAFFS_BLOCK_STATE_SCANNING,
++ /* Being scanned */
++
++ YAFFS_BLOCK_STATE_NEEDS_SCAN,
++ /* The block might have something on it (ie it is allocating or full,
++ * perhaps empty) but it needs to be scanned to determine its true
++ * state.
++ * This state is only valid during scanning.
++ * NB We tolerate empty because the pre-scanner might be incapable of
++ * deciding
++ * However, if this state is returned on a YAFFS2 device,
++ * then we expect a sequence number
++ */
++
++ YAFFS_BLOCK_STATE_EMPTY,
++ /* This block is empty */
++
++ YAFFS_BLOCK_STATE_ALLOCATING,
++ /* This block is partially allocated.
++ * At least one page holds valid data.
++ * This is the one currently being used for page
++ * allocation. Should never be more than one of these.
++ * If a block is only partially allocated at mount it is treated as
++ * full.
++ */
++
++ YAFFS_BLOCK_STATE_FULL,
++ /* All the pages in this block have been allocated.
++ * If a block was only partially allocated when mounted we treat
++ * it as fully allocated.
++ */
++
++ YAFFS_BLOCK_STATE_DIRTY,
++ /* The block was full and now all chunks have been deleted.
++ * Erase me, reuse me.
++ */
++
++ YAFFS_BLOCK_STATE_CHECKPOINT,
++ /* This block is assigned to holding checkpoint data. */
++
++ YAFFS_BLOCK_STATE_COLLECTING,
++ /* This block is being garbage collected */
++
++ YAFFS_BLOCK_STATE_DEAD
++ /* This block has failed and is not in use */
++};
++
++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++struct yaffs_block_info {
++
++ s32 soft_del_pages:10; /* number of soft deleted pages */
++ s32 pages_in_use:10; /* number of pages in use */
++ u32 block_state:4; /* One of the above block states. */
++ /* NB use unsigned because enum is sometimes
++ * an int */
++ u32 needs_retiring:1; /* Data has failed on this block, */
++ /*need to get valid data off and retire*/
++ u32 skip_erased_check:1;/* Skip the erased check on this block */
++ u32 gc_prioritise:1; /* An ECC check or blank check has failed.
++ Block should be prioritised for GC */
++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc
++ failures on this block and tried to reuse it */
++ u32 has_summary:1; /* The block has a summary */
++
++ u32 has_shrink_hdr:1; /* This block has at least one shrink header */
++ u32 seq_number; /* block sequence number for yaffs2 */
++
++};
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++struct yaffs_obj_hdr {
++ enum yaffs_obj_type type;
++
++ /* Apply to everything */
++ int parent_obj_id;
++ u16 sum_no_longer_used; /* checksum of name. No longer used */
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ /* The following apply to all object types except for hard links */
++ u32 yst_mode; /* protection */
++
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++
++ /* File size applies to files only */
++ u32 file_size_low;
++
++ /* Equivalent object id applies to hard links only. */
++ int equiv_id;
++
++ /* Alias is for symlinks only. */
++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++ u32 yst_rdev; /* stuff for block and char devices (major/min) */
++
++ u32 win_ctime[2];
++ u32 win_atime[2];
++ u32 win_mtime[2];
++
++ u32 inband_shadowed_obj_id;
++ u32 inband_is_shrink;
++
++ u32 file_size_high;
++ u32 reserved[1];
++ int shadows_obj; /* This object header shadows the
++ specified object if > 0 */
++
++ /* is_shrink applies to object headers written when wemake a hole. */
++ u32 is_shrink;
++
++};
++
++/*--------------------------- Tnode -------------------------- */
++
++struct yaffs_tnode {
++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
++};
++
++/*------------------------ Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++struct yaffs_file_var {
++ loff_t file_size;
++ loff_t scanned_size;
++ loff_t shrink_size;
++ int top_level;
++ struct yaffs_tnode *top;
++};
++
++struct yaffs_dir_var {
++ struct list_head children; /* list of child links */
++ struct list_head dirty; /* Entry for list of dirty directories */
++};
++
++struct yaffs_symlink_var {
++ YCHAR *alias;
++};
++
++struct yaffs_hardlink_var {
++ struct yaffs_obj *equiv_obj;
++ u32 equiv_id;
++};
++
++union yaffs_obj_var {
++ struct yaffs_file_var file_variant;
++ struct yaffs_dir_var dir_variant;
++ struct yaffs_symlink_var symlink_variant;
++ struct yaffs_hardlink_var hardlink_variant;
++};
++
++struct yaffs_obj {
++ u8 deleted:1; /* This should only apply to unlinked files. */
++ u8 soft_del:1; /* it has also been soft deleted */
++ u8 unlinked:1; /* An unlinked file.*/
++ u8 fake:1; /* A fake object has no presence on NAND. */
++ u8 rename_allowed:1; /* Some objects cannot be renamed. */
++ u8 unlink_allowed:1;
++ u8 dirty:1; /* the object needs to be written to flash */
++ u8 valid:1; /* When the file system is being loaded up, this
++ * object might be created before the data
++ * is available
++ * ie. file data chunks encountered before
++ * the header.
++ */
++ u8 lazy_loaded:1; /* This object has been lazy loaded and
++ * is missing some detail */
++
++ u8 defered_free:1; /* Object is removed from NAND, but is
++ * still in the inode cache.
++ * Free of object is defered.
++ * until the inode is released.
++ */
++ u8 being_created:1; /* This object is still being created
++ * so skip some verification checks. */
++ u8 is_shadowed:1; /* This object is shadowed on the way
++ * to being renamed. */
++
++ u8 xattr_known:1; /* We know if this has object has xattribs
++ * or not. */
++ u8 has_xattr:1; /* This object has xattribs.
++ * Only valid if xattr_known. */
++
++ u8 serial; /* serial number of chunk in NAND.*/
++ u16 sum; /* sum of the name to speed searching */
++
++ struct yaffs_dev *my_dev; /* The device I'm on */
++
++ struct list_head hash_link; /* list of objects in hash bucket */
++
++ struct list_head hard_links; /* hard linked object chain*/
++
++ /* directory structure stuff */
++ /* also used for linking up the free list */
++ struct yaffs_obj *parent;
++ struct list_head siblings;
++
++ /* Where's my object header in NAND? */
++ int hdr_chunk;
++
++ int n_data_chunks; /* Number of data chunks for this file. */
++
++ u32 obj_id; /* the object id value */
++
++ u32 yst_mode;
++
++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
++
++#ifdef CONFIG_YAFFS_WINCE
++ u32 win_ctime[2];
++ u32 win_mtime[2];
++ u32 win_atime[2];
++#else
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++#endif
++
++ u32 yst_rdev;
++
++ void *my_inode;
++
++ enum yaffs_obj_type variant_type;
++
++ union yaffs_obj_var variant;
++
++};
++
++struct yaffs_obj_bucket {
++ struct list_head list;
++ int count;
++};
++
++/* yaffs_checkpt_obj holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++struct yaffs_checkpt_obj {
++ int struct_type;
++ u32 obj_id;
++ u32 parent_id;
++ int hdr_chunk;
++ enum yaffs_obj_type variant_type:3;
++ u8 deleted:1;
++ u8 soft_del:1;
++ u8 unlinked:1;
++ u8 fake:1;
++ u8 rename_allowed:1;
++ u8 unlink_allowed:1;
++ u8 serial;
++ int n_data_chunks;
++ loff_t size_or_equiv_obj;
++};
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few.
++ */
++
++struct yaffs_buffer {
++ u8 *buffer;
++ int in_use;
++};
++
++/*----------------- Device ---------------------------------*/
++
++struct yaffs_param {
++ const YCHAR *name;
++
++ /*
++ * Entry parameters set up way early. Yaffs sets up the rest.
++ * The structure should be zeroed out before use so that unused
++ * and default values are zero.
++ */
++
++ int inband_tags; /* Use unband tags */
++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
++ be a power of 2 */
++ int chunks_per_block; /* does not need to be a power of 2 */
++ int spare_bytes_per_chunk; /* spare area size */
++ int start_block; /* Start block we're allowed to use */
++ int end_block; /* End block we're allowed to use */
++ int n_reserved_blocks; /* Tuneable so that we can reduce
++ * reserved blocks on NOR and RAM. */
++
++ int n_caches; /* If <= 0, then short op caching is disabled,
++ * else the number of short op caches.
++ */
++ int cache_bypass_aligned; /* If non-zero then bypass the cache for
++ * aligned writes.
++ */
++
++ int use_nand_ecc; /* Flag to decide whether or not to use
++ * NAND driver ECC on data (yaffs1) */
++ int tags_9bytes; /* Use 9 byte tags */
++ int no_tags_ecc; /* Flag to decide whether or not to do ECC
++ * on packed tags (yaffs2) */
++
++ int is_yaffs2; /* Use yaffs2 mode on this device */
++
++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
++
++ int refresh_period; /* How often to check for a block refresh */
++
++ /* Checkpoint control. Can be set before or after initialisation */
++ u8 skip_checkpt_rd;
++ u8 skip_checkpt_wr;
++
++ int enable_xattr; /* Enable xattribs */
++
++ int max_objects; /*
++ * Set to limit the number of objects created.
++ * 0 = no limit.
++ */
++
++ /* The remove_obj_fn function must be supplied by OS flavours that
++ * need it.
++ * yaffs direct uses it to implement the faster readdir.
++ * Linux uses it to protect the directory during unlocking.
++ */
++ void (*remove_obj_fn) (struct yaffs_obj *obj);
++
++ /* Callback to mark the superblock dirty */
++ void (*sb_dirty_fn) (struct yaffs_dev *dev);
++
++ /* Callback to control garbage collection. */
++ unsigned (*gc_control_fn) (struct yaffs_dev *dev);
++
++ /* Debug control flags. Don't use unless you know what you're doing */
++ int use_header_file_size; /* Flag to determine if we should use
++ * file sizes from the header */
++ int disable_lazy_load; /* Disable lazy loading on this device */
++ int wide_tnodes_disabled; /* Set to disable wide tnodes */
++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of
++ * softdeletion. */
++
++ int defered_dir_update; /* Set to defer directory updates */
++
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ int auto_unicode;
++#endif
++ int always_check_erased; /* Force chunk erased check always on */
++
++ int disable_summary;
++ int disable_bad_block_marking;
++
++};
++
++struct yaffs_driver {
++ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len);
++ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result);
++ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_initialise_fn) (struct yaffs_dev *dev);
++ int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
++};
++
++struct yaffs_tags_handler {
++ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags);
++ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags);
++
++ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++};
++
++struct yaffs_dev {
++ struct yaffs_param param;
++ struct yaffs_driver drv;
++ struct yaffs_tags_handler tagger;
++
++ /* Context storage. Holds extra OS specific data for this device */
++
++ void *os_context;
++ void *driver_context;
++
++ struct list_head dev_list;
++
++ int ll_init;
++ /* Runtime parameters. Set up by YAFFS. */
++ int data_bytes_per_chunk;
++
++ /* Non-wide tnode stuff */
++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
++ * the tnodes are not wide enough.
++ */
++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
++
++ /* Stuff to support wide tnodes */
++ u32 tnode_width;
++ u32 tnode_mask;
++ u32 tnode_size;
++
++ /* Stuff for figuring out file offset to chunk conversions */
++ u32 chunk_shift; /* Shift value */
++ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
++ u32 chunk_mask; /* Mask to use for power-of-2 case */
++
++ int is_mounted;
++ int read_only;
++ int is_checkpointed;
++
++ /* Stuff to support block offsetting to support start block zero */
++ int internal_start_block;
++ int internal_end_block;
++ int block_offset;
++ int chunk_offset;
++
++ /* Runtime checkpointing stuff */
++ int checkpt_page_seq; /* running sequence number of checkpt pages */
++ int checkpt_byte_count;
++ int checkpt_byte_offs;
++ u8 *checkpt_buffer;
++ int checkpt_open_write;
++ int blocks_in_checkpt;
++ int checkpt_cur_chunk;
++ int checkpt_cur_block;
++ int checkpt_next_block;
++ int *checkpt_block_list;
++ int checkpt_max_blocks;
++ u32 checkpt_sum;
++ u32 checkpt_xor;
++
++ int checkpoint_blocks_required; /* Number of blocks needed to store
++ * current checkpoint set */
++
++ /* Block Info */
++ struct yaffs_block_info *block_info;
++ u8 *chunk_bits; /* bitmap of chunks in use */
++ u8 block_info_alt:1; /* allocated using alternative alloc */
++ u8 chunk_bits_alt:1; /* allocated using alternative alloc */
++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
++ * Must be consistent with chunks_per_block.
++ */
++
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int alloc_block_finder; /* Used to search for next allocation block */
++
++ /* Object and Tnode memory management */
++ void *allocator;
++ int n_obj;
++ int n_tnodes;
++
++ int n_hardlinks;
++
++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
++ u32 bucket_finder;
++
++ int n_free_chunks;
++
++ /* Garbage collection control */
++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
++ u32 n_clean_ups;
++
++ unsigned has_pending_prioritised_gc; /* We think this device might
++ have pending prioritised gcs */
++ unsigned gc_disable;
++ unsigned gc_block_finder;
++ unsigned gc_dirtiest;
++ unsigned gc_pages_in_use;
++ unsigned gc_not_done;
++ unsigned gc_block;
++ unsigned gc_chunk;
++ unsigned gc_skip;
++ struct yaffs_summary_tags *gc_sum_tags;
++
++ /* Special directories */
++ struct yaffs_obj *root_dir;
++ struct yaffs_obj *lost_n_found;
++
++ int buffered_block; /* Which block is buffered here? */
++ int doing_buffered_block_rewrite;
++
++ struct yaffs_cache *cache;
++ int cache_last_use;
++
++ /* Stuff for background deletion and unlinked files. */
++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
++ files live. */
++ struct yaffs_obj *del_dir; /* Directory where deleted objects are
++ sent to disappear. */
++ struct yaffs_obj *unlinked_deletion; /* Current file being
++ background deleted. */
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* Temporary buffer management */
++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
++ int max_temp;
++ int temp_in_use;
++ int unmanaged_buffer_allocs;
++ int unmanaged_buffer_deallocs;
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ allocating block */
++ unsigned oldest_dirty_seq;
++ unsigned oldest_dirty_block;
++
++ /* Block refreshing */
++ int refresh_skip; /* A skip down counter.
++ * Refresh happens when this gets to zero. */
++
++ /* Dirty directory handling */
++ struct list_head dirty_dirs; /* List of dirty directories */
++
++ /* Summary */
++ int chunks_per_summary;
++ struct yaffs_summary_tags *sum_tags;
++
++ /* Statistics */
++ u32 n_page_writes;
++ u32 n_page_reads;
++ u32 n_erasures;
++ u32 n_bad_queries;
++ u32 n_bad_markings;
++ u32 n_erase_failures;
++ u32 n_gc_copies;
++ u32 all_gcs;
++ u32 passive_gc_count;
++ u32 oldest_dirty_gc_count;
++ u32 n_gc_blocks;
++ u32 bg_gcs;
++ u32 n_retried_writes;
++ u32 n_retired_blocks;
++ u32 n_ecc_fixed;
++ u32 n_ecc_unfixed;
++ u32 n_tags_ecc_fixed;
++ u32 n_tags_ecc_unfixed;
++ u32 n_deletions;
++ u32 n_unmarked_deletions;
++ u32 refresh_count;
++ u32 cache_hits;
++ u32 tags_used;
++ u32 summary_used;
++
++};
++
++/* The CheckpointDevice structure holds the device information that changes
++ *at runtime and must be preserved over unmount/mount cycles.
++ */
++struct yaffs_checkpt_dev {
++ int struct_type;
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int n_free_chunks;
++
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ * allocating block */
++
++};
++
++struct yaffs_checkpt_validity {
++ int struct_type;
++ u32 magic;
++ u32 version;
++ u32 head;
++};
++
++struct yaffs_shadow_fixer {
++ int obj_id;
++ int shadowed_id;
++ struct yaffs_shadow_fixer *next;
++};
++
++/* Structure for doing xattr modifications */
++struct yaffs_xattr_mod {
++ int set; /* If 0 then this is a deletion */
++ const YCHAR *name;
++ const void *data;
++ int size;
++ int flags;
++ int result;
++};
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_guts_initialise(struct yaffs_dev *dev);
++void yaffs_deinitialise(struct yaffs_dev *dev);
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++ struct yaffs_obj *new_dir, const YCHAR * new_name);
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
++int yaffs_del_obj(struct yaffs_obj *obj);
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type);
++
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
++int yaffs_get_obj_inode(struct yaffs_obj *obj);
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
++int yaffs_get_obj_link_count(struct yaffs_obj *obj);
++
++/* File operations */
++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
++ int n_bytes);
++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid);
++
++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
++
++/* Flushing and checkpointing */
++void yaffs_flush_whole_cache(struct yaffs_dev *dev);
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev);
++int yaffs_checkpoint_restore(struct yaffs_dev *dev);
++
++/* Directory operations */
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid);
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
++ const YCHAR *name);
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
++
++/* Link operations */
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
++ struct yaffs_obj *equiv_obj);
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
++
++/* Symlink operations */
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias);
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev);
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
++ const void *value, int size, int flags);
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
++ int size);
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
++
++/* Special directories */
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj);
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
++
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
++
++/* Debug dump */
++int yaffs_dump_obj(struct yaffs_obj *obj);
++
++void yaffs_guts_test(struct yaffs_dev *dev);
++int yaffs_guts_ll_init(struct yaffs_dev *dev);
++
++
++/* A few useful functions to be used within the core files*/
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn);
++int yaffs_check_ff(u8 *buffer, int n_bytes);
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type);
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan);
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh);
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
++YCHAR *yaffs_clone_str(const YCHAR *str);
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
++ int force, int is_shrink, int shadows,
++ struct yaffs_xattr_mod *xop);
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning);
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn);
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id);
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos);
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev);
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out);
++/*
++ * Marshalling functions to get loff_t file sizes into aand out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
++loff_t yaffs_max_file_size(struct yaffs_dev *dev);
++
++/*
++ * Debug function to count number of blocks in each state
++ * NB Needs to be called with correct number of integers
++ */
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_linux.h linux-3.10.40/fs/yaffs2/yaffs_linux.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_linux.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_LINUX_H__
++#define __YAFFS_LINUX_H__
++
++#include "yportenv.h"
++
++struct yaffs_linux_context {
++ struct list_head context_list; /* List of these we have mounted */
++ struct yaffs_dev *dev;
++ struct super_block *super;
++ struct task_struct *bg_thread; /* Background thread for this device */
++ int bg_running;
++ struct mutex gross_lock; /* Gross locking mutex*/
++ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
++ * at compile time so we have to allocate it.
++ */
++ struct list_head search_contexts;
++ struct task_struct *readdir_process;
++ unsigned mount_id;
++ int dirty;
++};
++
++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
++
++#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
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_mtdif.c linux-3.10.40/fs/yaffs2/yaffs_mtdif.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_mtdif.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,309 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/major.h"
++#include "linux/mtd/nand.h"
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_linux.h"
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++#define mtd_erase(m, ei) (m)->erase(m, ei)
++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
++#endif
++
++
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ u32 addr =
++ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ struct erase_info ei;
++ int retval = 0;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++
++static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
++ dev, nand_chunk, data, data_len, oob, oob_len);
++
++ if (!data || !data_len) {
++ data = NULL;
++ data_len = 0;
++ }
++
++ if (!oob || !oob_len) {
++ oob = NULL;
++ oob_len = 0;
++ }
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = (u8 *)data;
++ ops.oobbuf = (u8 *)oob;
++
++ retval = mtd_write_oob(mtd, addr, &ops);
++ if (retval) {
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "write_oob failed, chunk %d, mtd error %d",
++ nand_chunk, retval);
++ }
++ return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = data;
++ ops.oobbuf = oob;
++
++#if (MTD_VERSION_CODE < MTD_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",
++ nand_chunk, retval);
++
++ switch (retval) {
++ case 0:
++ /* no error */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++
++ case -EUCLEAN:
++ /* MTD's ECC fixed the data */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ break;
++
++ case -EBADMSG:
++ default:
++ /* MTD's ECC could not fix the data */
++ dev->n_ecc_unfixed++;
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ loff_t addr;
++ struct erase_info ei;
++ int retval = 0;
++ u32 block_size;
++
++ block_size = dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ addr = ((loff_t) block_no) * block_size;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = block_size;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
++
++ retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
++
++ retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_initialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++
++ drv->drv_write_chunk_fn = yaffs_mtd_write;
++ drv->drv_read_chunk_fn = yaffs_mtd_read;
++ drv->drv_erase_fn = yaffs_mtd_erase;
++ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
++ drv->drv_check_bad_fn = yaffs_mtd_check_bad;
++ drv->drv_initialise_fn = yaffs_mtd_initialise;
++ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
++}
++
++
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
++{
++ struct mtd_info *mtd;
++
++ mtd = yaffs_get_mtd_device(sdev);
++
++ /* Check it's an mtd device..... */
++ if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
++ return NULL; /* This isn't an mtd device */
++
++ /* Check it's NAND */
++ if (mtd->type != MTD_NANDFLASH) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device is not NAND it's type %d",
++ mtd->type);
++ return NULL;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
++ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
++ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++ yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
++#else
++ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
++#endif
++
++ return mtd;
++}
++
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++{
++ if (yaffs_version == 2) {
++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++ !inband_tags) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not have the right page sizes"
++ );
++ return -1;
++ }
++ } else {
++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not support have the right page sizes"
++ );
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++
++void yaffs_put_mtd_device(struct mtd_info *mtd)
++{
++ if(mtd)
++ put_mtd_device(mtd);
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_mtdif.h linux-3.10.40/fs/yaffs2/yaffs_mtdif.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_mtdif.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev);
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
++void yaffs_put_mtd_device(struct mtd_info *mtd);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_nameval.c linux-3.10.40/fs/yaffs2/yaffs_nameval.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_nameval.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This simple implementation of a name-value store assumes a small number of
++* values and fits into a small finite buffer.
++ *
++ * Each attribute is stored as a record:
++ * sizeof(int) bytes record size.
++ * strnlen+1 bytes name null terminated.
++ * nbytes value.
++ * ----------
++ * total size stored in record size
++ *
++ * This code has not been tested with unicode yet.
++ */
++
++#include "yaffs_nameval.h"
++
++#include "yportenv.h"
++
++static int nval_find(const char *xb, int xb_size, const YCHAR *name,
++ int *exist_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
++ name, size)) {
++ if (exist_size)
++ *exist_size = size;
++ return pos;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ if (exist_size)
++ *exist_size = 0;
++ return -ENODATA;
++}
++
++static int nval_used(const char *xb, int xb_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return pos;
++}
++
++int nval_del(char *xb, int xb_size, const YCHAR *name)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos < 0 || pos >= xb_size)
++ return -ENODATA;
++
++ /* Find size, shift rest over this record,
++ * then zero out the rest of buffer */
++ memcpy(&size, xb + pos, sizeof(int));
++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
++ memset(xb + (xb_size - size), 0, size);
++ return 0;
++}
++
++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
++ int bsize, int flags)
++{
++ int pos;
++ int namelen = strnlen(name, xb_size);
++ int reclen;
++ int size_exist = 0;
++ int space;
++ int start;
++
++ pos = nval_find(xb, xb_size, name, &size_exist);
++
++ if (flags & XATTR_CREATE && pos >= 0)
++ return -EEXIST;
++ if (flags & XATTR_REPLACE && pos < 0)
++ return -ENODATA;
++
++ start = nval_used(xb, xb_size);
++ space = xb_size - start + size_exist;
++
++ reclen = (sizeof(int) + namelen + 1 + bsize);
++
++ if (reclen > space)
++ return -ENOSPC;
++
++ if (pos >= 0) {
++ nval_del(xb, xb_size, name);
++ start = nval_used(xb, xb_size);
++ }
++
++ pos = start;
++
++ memcpy(xb + pos, &reclen, sizeof(int));
++ pos += sizeof(int);
++ strncpy((YCHAR *) (xb + pos), name, reclen);
++ pos += (namelen + 1);
++ memcpy(xb + pos, buf, bsize);
++ return 0;
++}
++
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos >= 0 && pos < xb_size) {
++
++ memcpy(&size, xb + pos, sizeof(int));
++ pos += sizeof(int); /* advance past record length */
++ size -= sizeof(int);
++
++ /* Advance over name string */
++ while (xb[pos] && size > 0 && pos < xb_size) {
++ pos++;
++ size--;
++ }
++ /*Advance over NUL */
++ pos++;
++ size--;
++
++ /* If bsize is zero then this is a size query.
++ * Return the size, but don't copy.
++ */
++ if (!bsize)
++ return size;
++
++ if (size <= bsize) {
++ memcpy(buf, xb + pos, size);
++ return size;
++ }
++ }
++ if (pos >= 0)
++ return -ERANGE;
++
++ return -ENODATA;
++}
++
++int nval_list(const char *xb, int xb_size, char *buf, int bsize)
++{
++ int pos = 0;
++ int size;
++ int name_len;
++ int ncopied = 0;
++ int filled = 0;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > sizeof(int) &&
++ size <= xb_size &&
++ (pos + size) < xb_size &&
++ !filled) {
++ pos += sizeof(int);
++ size -= sizeof(int);
++ name_len = strnlen((YCHAR *) (xb + pos), size);
++ if (ncopied + name_len + 1 < bsize) {
++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
++ buf += name_len;
++ *buf = '\0';
++ buf++;
++ if (sizeof(YCHAR) > 1) {
++ *buf = '\0';
++ buf++;
++ }
++ ncopied += (name_len + 1);
++ } else {
++ filled = 1;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return ncopied;
++}
++
++int nval_hasvalues(const char *xb, int xb_size)
++{
++ return nval_used(xb, xb_size) > 0;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_nameval.h linux-3.10.40/fs/yaffs2/yaffs_nameval.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_nameval.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __NAMEVAL_H__
++#define __NAMEVAL_H__
++
++#include "yportenv.h"
++
++int nval_del(char *xb, int xb_size, const YCHAR * name);
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++ int bsize, int flags);
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize);
++int nval_list(const char *xb, int xb_size, char *buf, int bsize);
++int nval_hasvalues(const char *xb, int xb_size);
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_nand.c linux-3.10.40/fs/yaffs2/yaffs_nand.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_nand.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,122 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++
++#include "yaffs_getblockinfo.h"
++#include "yaffs_summary.h"
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ struct yaffs_ext_tags local_tags;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_reads++;
++
++ /* If there are no tags provided use local tags. */
++ if (!tags)
++ tags = &local_tags;
++
++ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
++
++ struct yaffs_block_info *bi;
++ bi = yaffs_get_block_info(dev,
++ nand_chunk /
++ dev->param.chunks_per_block);
++ yaffs_handle_chunk_error(dev, bi);
++ }
++ return result;
++}
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_writes++;
++
++ if (!tags) {
++ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ tags->seq_number = dev->seq_number;
++ tags->chunk_used = 1;
++ yaffs_trace(YAFFS_TRACE_WRITE,
++ "Writing chunk %d tags %d %d",
++ nand_chunk, tags->obj_id, tags->chunk_id);
++
++ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
++ buffer, tags);
++
++ yaffs_summary_add(dev, tags, nand_chunk);
++
++ return result;
++}
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ block_no -= dev->block_offset;
++ dev->n_bad_markings++;
++
++ if (dev->param.disable_bad_block_marking)
++ return YAFFS_OK;
++
++ return dev->tagger.mark_bad_fn(dev, block_no);
++}
++
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ block_no -= dev->block_offset;
++ return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
++}
++
++int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ int result;
++
++ block_no -= dev->block_offset;
++ dev->n_erasures++;
++ result = dev->drv.drv_erase_fn(dev, block_no);
++ return result;
++}
++
++int yaffs_init_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_initialise_fn)
++ return dev->drv.drv_initialise_fn(dev);
++ return YAFFS_OK;
++}
++
++int yaffs_deinit_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_deinitialise_fn)
++ return dev->drv.drv_deinitialise_fn(dev);
++ return YAFFS_OK;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_nand.h linux-3.10.40/fs/yaffs2/yaffs_nand.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_nand.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ unsigned *seq_number);
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
++
++int yaffs_init_nand(struct yaffs_dev *dev);
++int yaffs_deinit_nand(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.10.40/fs/yaffs2/yaffs_packedtags1.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_packedtags1.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++static const u8 all_ff[20] = {
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t)
++{
++ pt->chunk_id = t->chunk_id;
++ pt->serial_number = t->serial_number;
++ pt->n_bytes = t->n_bytes;
++ pt->obj_id = t->obj_id;
++ pt->ecc = 0;
++ pt->deleted = (t->is_deleted) ? 0 : 1;
++ pt->unused_stuff = 0;
++ pt->should_be_ff = 0xffffffff;
++}
++
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt)
++{
++
++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
++ t->block_bad = 0;
++ if (pt->should_be_ff != 0xffffffff)
++ t->block_bad = 1;
++ t->chunk_used = 1;
++ t->obj_id = pt->obj_id;
++ t->chunk_id = pt->chunk_id;
++ t->n_bytes = pt->n_bytes;
++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ t->is_deleted = (pt->deleted) ? 0 : 1;
++ t->serial_number = pt->serial_number;
++ } else {
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++ }
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.10.40/fs/yaffs2/yaffs_packedtags1.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_packedtags1.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++struct yaffs_packed_tags1 {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 deleted:1;
++ u32 unused_stuff:1;
++ unsigned should_be_ff;
++
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt);
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.10.40/fs/yaffs2/yaffs_packedtags2.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_packedtags2.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunk_id */
++
++#define EXTRA_HEADER_INFO_FLAG 0x80000000
++#define EXTRA_SHRINK_FLAG 0x40000000
++#define EXTRA_SHADOWS_FLAG 0x20000000
++#define EXTRA_SPARE_FLAGS 0x10000000
++
++#define ALL_EXTRA_FLAGS 0xf0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
++
++static void yaffs_dump_packed_tags2_tags_only(
++ const struct yaffs_packed_tags2_tags_only *ptt)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "packed tags obj %d chunk %d byte %d seq %d",
++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
++}
++
++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
++{
++ yaffs_dump_packed_tags2_tags_only(&pt->t);
++}
++
++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
++ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
++ t->seq_number);
++
++}
++
++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
++{
++ if (t->chunk_id != 0 || !t->extra_available)
++ return 0;
++
++ /* Check if the file size is too long to store */
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
++ (t->extra_file_size >> 31) != 0)
++ return 0;
++ return 1;
++}
++
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
++ const struct yaffs_ext_tags *t)
++{
++ ptt->chunk_id = t->chunk_id;
++ ptt->seq_number = t->seq_number;
++ ptt->n_bytes = t->n_bytes;
++ ptt->obj_id = t->obj_id;
++
++ /* Only store extra tags for object headers.
++ * If it is a file then only store if the file size is short\
++ * enough to fit.
++ */
++ if (yaffs_check_tags_extra_packable(t)) {
++ /* Store the extra header info instead */
++ /* We save the parent object in the chunk_id */
++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
++ if (t->extra_is_shrink)
++ ptt->chunk_id |= EXTRA_SHRINK_FLAG;
++ if (t->extra_shadows)
++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
++
++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ ptt->n_bytes = t->extra_equiv_id;
++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ ptt->n_bytes = (unsigned) t->extra_file_size;
++ else
++ ptt->n_bytes = 0;
++ }
++
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc)
++{
++ yaffs_pack_tags2_tags_only(&pt->t, t);
++
++ if (tags_ecc)
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc);
++}
++
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *ptt)
++{
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++
++ if (ptt->seq_number == 0xffffffff)
++ return;
++
++ t->block_bad = 0;
++ t->chunk_used = 1;
++ t->obj_id = ptt->obj_id;
++ t->chunk_id = ptt->chunk_id;
++ t->n_bytes = ptt->n_bytes;
++ t->is_deleted = 0;
++ t->serial_number = 0;
++ t->seq_number = ptt->seq_number;
++
++ /* Do extra header info stuff */
++ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
++ t->chunk_id = 0;
++ t->n_bytes = 0;
++
++ t->extra_available = 1;
++ t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
++ t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
++ t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
++ t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ t->extra_equiv_id = ptt->n_bytes;
++ else
++ t->extra_file_size = ptt->n_bytes;
++ }
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc)
++{
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ if (pt->t.seq_number != 0xffffffff && tags_ecc) {
++ /* Chunk is in use and we need to do ECC */
++
++ struct yaffs_ecc_other ecc;
++ int result;
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &ecc);
++ result =
++ yaffs_ecc_correct_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc, &ecc);
++ switch (result) {
++ case 0:
++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++ case 1:
++ ecc_result = YAFFS_ECC_RESULT_FIXED;
++ break;
++ case -1:
++ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ break;
++ default:
++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ }
++ }
++ yaffs_unpack_tags2_tags_only(t, &pt->t);
++
++ t->ecc_result = ecc_result;
++
++ yaffs_dump_packed_tags2(pt);
++ yaffs_dump_tags2(t);
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.10.40/fs/yaffs2/yaffs_packedtags2.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_packedtags2.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++struct yaffs_packed_tags2_tags_only {
++ unsigned seq_number;
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++struct yaffs_packed_tags2 {
++ struct yaffs_packed_tags2_tags_only t;
++ struct yaffs_ecc_other ecc;
++};
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc);
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *pt);
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_summary.c linux-3.10.40/fs/yaffs2/yaffs_summary.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_summary.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_summary.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,312 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Summaries write the useful part of the tags for the chunks in a block into an
++ * an array which is written to the last n chunks of the block.
++ * Reading the summaries gives all the tags for the block in one read. Much
++ * faster.
++ *
++ * Chunks holding summaries are marked with tags making it look like
++ * they are part of a fake file.
++ *
++ * The summary could also be used during gc.
++ *
++ */
++
++#include "yaffs_summary.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_bitmap.h"
++
++/*
++ * The summary is built up in an array of summary tags.
++ * This gets written to the last one or two (maybe more) chunks in a block.
++ * A summary header is written as the first part of each chunk of summary data.
++ * The summary header must match or the summary is rejected.
++ */
++
++/* Summary tags don't need the sequence number because that is redundant. */
++struct yaffs_summary_tags {
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++/* Summary header */
++struct yaffs_summary_header {
++ unsigned version; /* Must match current version */
++ unsigned block; /* Must be this block */
++ unsigned seq; /* Must be this sequence number */
++ unsigned sum; /* Just add up all the bytes in the tags */
++};
++
++
++static void yaffs_summary_clear(struct yaffs_dev *dev)
++{
++ if (!dev->sum_tags)
++ return;
++ memset(dev->sum_tags, 0, dev->chunks_per_summary *
++ sizeof(struct yaffs_summary_tags));
++}
++
++
++void yaffs_summary_deinit(struct yaffs_dev *dev)
++{
++ kfree(dev->sum_tags);
++ dev->sum_tags = NULL;
++ kfree(dev->gc_sum_tags);
++ dev->gc_sum_tags = NULL;
++ dev->chunks_per_summary = 0;
++}
++
++int yaffs_summary_init(struct yaffs_dev *dev)
++{
++ int sum_bytes;
++ int chunks_used; /* Number of chunks used by summary */
++ int sum_tags_bytes;
++
++ sum_bytes = dev->param.chunks_per_block *
++ sizeof(struct yaffs_summary_tags);
++
++ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
++ (dev->data_bytes_per_chunk -
++ sizeof(struct yaffs_summary_header));
++
++ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ if (!dev->sum_tags || !dev->gc_sum_tags) {
++ yaffs_summary_deinit(dev);
++ return YAFFS_FAIL;
++ }
++
++ yaffs_summary_clear(dev);
++
++ return YAFFS_OK;
++}
++
++static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
++{
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int i;
++ unsigned sum = 0;
++
++ i = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ while (i > 0) {
++ sum += *sum_buffer;
++ sum_buffer++;
++ i--;
++ }
++
++ return sum;
++}
++
++static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int n_bytes;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ memset(&tags, 0, sizeof(struct yaffs_ext_tags));
++ tags.obj_id = YAFFS_OBJECTID_SUMMARY;
++ tags.chunk_id = 1;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ hdr.version = YAFFS_SUMMARY_VERSION;
++ hdr.block = blk;
++ hdr.seq = bi->seq_number;
++ hdr.sum = yaffs_summary_sum(dev);
++
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ memcpy(buffer, &hdr, sizeof(hdr));
++ memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
++ tags.n_bytes = this_tx + sizeof(hdr);
++ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (result != YAFFS_OK)
++ break;
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ dev->n_free_chunks--;
++
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ tags.chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++
++ if (result == YAFFS_OK)
++ bi->has_summary = 1;
++
++
++ return result;
++}
++
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)st;
++ int n_bytes;
++ int chunk_id;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ int sum_tags_bytes;
++
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = blk * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ chunk_id = 1;
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (tags.chunk_id != chunk_id ||
++ tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
++ tags.chunk_used == 0 ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.n_bytes != (this_tx + sizeof(hdr)))
++ result = YAFFS_FAIL;
++ if (result != YAFFS_OK)
++ break;
++
++ if (st == dev->sum_tags) {
++ /* If we're scanning then update the block info */
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ }
++ memcpy(&hdr, buffer, sizeof(hdr));
++ memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (result == YAFFS_OK) {
++ /* Verify header */
++ if (hdr.version != YAFFS_SUMMARY_VERSION ||
++ hdr.seq != bi->seq_number ||
++ hdr.sum != yaffs_summary_sum(dev))
++ result = YAFFS_FAIL;
++ }
++
++ if (st == dev->sum_tags && result == YAFFS_OK)
++ bi->has_summary = 1;
++
++ return result;
++}
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_nand)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
++ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
++
++ if (!dev->sum_tags)
++ return YAFFS_OK;
++
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ yaffs_pack_tags2_tags_only(&tags_only, tags);
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ sum_tags->chunk_id = tags_only.chunk_id;
++ sum_tags->n_bytes = tags_only.n_bytes;
++ sum_tags->obj_id = tags_only.obj_id;
++
++ if (chunk_in_block == dev->chunks_per_summary - 1) {
++ /* Time to write out the summary */
++ yaffs_summary_write(dev, block_in_nand);
++ yaffs_summary_clear(dev);
++ yaffs_skip_rest_of_block(dev);
++ }
++ }
++ return YAFFS_OK;
++}
++
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ tags_only.chunk_id = sum_tags->chunk_id;
++ tags_only.n_bytes = sum_tags->n_bytes;
++ tags_only.obj_id = sum_tags->obj_id;
++ yaffs_unpack_tags2_tags_only(tags, &tags_only);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int i;
++
++ if (!bi->has_summary)
++ return;
++
++ for (i = dev->chunks_per_summary;
++ i < dev->param.chunks_per_block;
++ i++) {
++ if (yaffs_check_chunk_bit(dev, blk, i)) {
++ yaffs_clear_chunk_bit(dev, blk, i);
++ bi->pages_in_use--;
++ dev->n_free_chunks++;
++ }
++ }
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_summary.h linux-3.10.40/fs/yaffs2/yaffs_summary.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_summary.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_summary.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_SUMMARY_H__
++#define __YAFFS_SUMMARY_H__
++
++#include "yaffs_packedtags2.h"
++
++
++int yaffs_summary_init(struct yaffs_dev *dev);
++void yaffs_summary_deinit(struct yaffs_dev *dev);
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk);
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
++
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.10.40/fs/yaffs2/yaffs_tagscompat.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_tagscompat.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,381 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++
++
++/********** Tags ECC calculations *********/
++
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
++{
++ /* Calculate an ecc */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++ unsigned i, j;
++ unsigned ecc = 0;
++ unsigned bit = 0;
++
++ tags->ecc = 0;
++
++ for (i = 0; i < 8; i++) {
++ for (j = 1; j & 0xff; j <<= 1) {
++ bit++;
++ if (b[i] & j)
++ ecc ^= bit;
++ }
++ }
++ tags->ecc = ecc;
++}
++
++int yaffs_check_tags_ecc(struct yaffs_tags *tags)
++{
++ unsigned ecc = tags->ecc;
++
++ yaffs_calc_tags_ecc(tags);
++
++ ecc ^= tags->ecc;
++
++ if (ecc && ecc <= 64) {
++ /* TODO: Handle the failure better. Retire? */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++
++ ecc--;
++
++ b[ecc / 8] ^= (1 << (ecc & 7));
++
++ /* Now recvalc the ecc */
++ yaffs_calc_tags_ecc(tags);
++
++ return 1; /* recovered error */
++ } else if (ecc) {
++ /* Wierd ecc failure value */
++ /* TODO Need to do somethiong here */
++ return -1; /* unrecovered error */
++ }
++ return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++
++ yaffs_calc_tags_ecc(tags_ptr);
++
++ spare_ptr->tb0 = tu->as_bytes[0];
++ spare_ptr->tb1 = tu->as_bytes[1];
++ spare_ptr->tb2 = tu->as_bytes[2];
++ spare_ptr->tb3 = tu->as_bytes[3];
++ spare_ptr->tb4 = tu->as_bytes[4];
++ spare_ptr->tb5 = tu->as_bytes[5];
++ spare_ptr->tb6 = tu->as_bytes[6];
++ spare_ptr->tb7 = tu->as_bytes[7];
++}
++
++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
++ struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++ int result;
++
++ tu->as_bytes[0] = spare_ptr->tb0;
++ tu->as_bytes[1] = spare_ptr->tb1;
++ tu->as_bytes[2] = spare_ptr->tb2;
++ tu->as_bytes[3] = spare_ptr->tb3;
++ tu->as_bytes[4] = spare_ptr->tb4;
++ tu->as_bytes[5] = spare_ptr->tb5;
++ tu->as_bytes[6] = spare_ptr->tb6;
++ tu->as_bytes[7] = spare_ptr->tb7;
++
++ result = yaffs_check_tags_ecc(tags_ptr);
++ if (result > 0)
++ dev->n_tags_ecc_fixed++;
++ else if (result < 0)
++ dev->n_tags_ecc_unfixed++;
++}
++
++static void yaffs_spare_init(struct yaffs_spare *spare)
++{
++ memset(spare, 0xff, sizeof(struct yaffs_spare));
++}
++
++static int yaffs_wr_nand(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ struct yaffs_spare *spare)
++{
++ int data_size = dev->data_bytes_per_chunk;
++
++ return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, sizeof(*spare));
++}
++
++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data,
++ struct yaffs_spare *spare,
++ enum yaffs_ecc_result *ecc_result,
++ int correct_errors)
++{
++ int ret_val;
++ struct yaffs_spare local_spare;
++ int data_size;
++ int spare_size;
++ int ecc_result1, ecc_result2;
++ u8 calc_ecc[3];
++
++ if (!spare) {
++ /* If we don't have a real spare, then we use a local one. */
++ /* Need this for the calculation of the ecc */
++ spare = &local_spare;
++ }
++ data_size = dev->data_bytes_per_chunk;
++ spare_size = sizeof(struct yaffs_spare);
++
++ if (dev->param.use_nand_ecc)
++ return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, spare_size,
++ ecc_result);
++
++
++ /* Handle the ECC at this level. */
++
++ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *)spare, spare_size,
++ NULL);
++ if (!data || !correct_errors)
++ return ret_val;
++
++ /* Do ECC correction if needed. */
++ yaffs_ecc_calc(data, calc_ecc);
++ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
++ yaffs_ecc_calc(&data[256], calc_ecc);
++ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
++
++ if (ecc_result1 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result1 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result2 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result2 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result1 || ecc_result2) {
++ /* We had a data problem on this page */
++ yaffs_handle_rd_data_error(dev, nand_chunk);
++ }
++
++ if (ecc_result1 < 0 || ecc_result2 < 0)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ else if (ecc_result1 > 0 || ecc_result2 > 0)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ else
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ return ret_val;
++}
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++
++ /* Mark the block for retirement */
++ yaffs_get_block_info(dev, flash_block + dev->block_offset)->
++ needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>>Block %d marked for retirement",
++ flash_block);
++
++ /* TODO:
++ * Just do a garbage collection on the affected block
++ * then retire the block
++ * NB recursion
++ */
++}
++
++static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++
++ yaffs_spare_init(&spare);
++
++ if (ext_tags->is_deleted)
++ spare.page_status = 0;
++ else {
++ tags.obj_id = ext_tags->obj_id;
++ tags.chunk_id = ext_tags->chunk_id;
++
++ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
++ else
++ tags.n_bytes_msb = 3;
++
++ tags.serial_number = ext_tags->serial_number;
++
++ if (!dev->param.use_nand_ecc && data) {
++ yaffs_ecc_calc(data, spare.ecc1);
++ yaffs_ecc_calc(&data[256], spare.ecc2);
++ }
++
++ yaffs_load_tags_to_spare(&spare, &tags);
++ }
++ return yaffs_wr_nand(dev, nand_chunk, data, &spare);
++}
++
++static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ int deleted;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ if (!yaffs_rd_chunk_nand(dev, nand_chunk,
++ data, &spare, &ecc_result, 1))
++ return YAFFS_FAIL;
++
++ /* ext_tags may be NULL */
++ if (!ext_tags)
++ return YAFFS_OK;
++
++ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
++
++ ext_tags->is_deleted = deleted;
++ ext_tags->ecc_result = ecc_result;
++ ext_tags->block_bad = 0; /* We're reading it */
++ /* therefore it is not a bad block */
++ ext_tags->chunk_used =
++ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
++
++ if (ext_tags->chunk_used) {
++ yaffs_get_tags_from_spare(dev, &spare, &tags);
++ ext_tags->obj_id = tags.obj_id;
++ ext_tags->chunk_id = tags.chunk_id;
++ ext_tags->n_bytes = tags.n_bytes_lsb;
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ ext_tags->n_bytes |=
++ (((unsigned)tags.n_bytes_msb) << 10);
++
++ ext_tags->serial_number = tags.serial_number;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_spare spare;
++
++ memset(&spare, 0xff, sizeof(struct yaffs_spare));
++
++ spare.block_status = 'Y';
++
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
++ &spare);
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
++ NULL, &spare);
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ struct yaffs_spare spare0, spare1;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ enum yaffs_ecc_result dummy;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ *seq_number = 0;
++
++ /* Look for bad block markers in the first two chunks */
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
++ NULL, &spare0, &dummy, 0);
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
++ NULL, &spare1, &dummy, 0);
++
++ if (hweight8(spare0.block_status & spare1.block_status) < 7)
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ else
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++
++ return YAFFS_OK;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++ if(dev->param.is_yaffs2)
++ return;
++ if(!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
++ if(!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
++ if(!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++ if(!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.10.40/fs/yaffs2/yaffs_tagscompat.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_tagscompat.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++
++#include "yaffs_guts.h"
++
++#if 0
++
++
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++
++#endif
++
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev);
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
++int yaffs_check_tags_ecc(struct yaffs_tags *tags);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.10.40/fs/yaffs2/yaffs_tagsmarshall.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_tagsmarshall.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,199 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_packedtags2.h"
++
++static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ struct yaffs_packed_tags2 pt;
++ int retval;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_write chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ /* For yaffs2 writing there must be both data and tags.
++ * If we're using inband tags, then the tags are stuffed into
++ * the end of the data buffer.
++ */
++ if (!data || !tags)
++ BUG();
++ else if (dev->param.inband_tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)(data +
++ dev->
++ data_bytes_per_chunk);
++ yaffs_pack_tags2_tags_only(pt2tp, tags);
++ } else {
++ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
++ }
++
++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ (dev->param.inband_tags) ? NULL : packed_tags_ptr,
++ (dev->param.inband_tags) ? 0 : packed_tags_size);
++
++ return retval;
++}
++
++static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = 0;
++ int local_data = 0;
++ u8 spare_buffer[100];
++ enum yaffs_ecc_result ecc_result;
++
++ struct yaffs_packed_tags2 pt;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_read chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ if (dev->param.inband_tags) {
++ if (!data) {
++ local_data = 1;
++ data = yaffs_get_temp_buffer(dev);
++ }
++ }
++
++ if (dev->param.inband_tags || (data && !tags))
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ NULL, 0,
++ &ecc_result);
++ else if (tags)
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ spare_buffer, packed_tags_size,
++ &ecc_result);
++ else
++ BUG();
++
++
++ if (dev->param.inband_tags) {
++ if (tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)
++ &data[dev->data_bytes_per_chunk];
++ yaffs_unpack_tags2_tags_only(tags, pt2tp);
++ }
++ } else if (tags) {
++ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
++ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
++ }
++
++ if (local_data)
++ yaffs_release_temp_buffer(dev, data);
++
++ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ dev->n_ecc_unfixed++;
++ }
++
++ if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
++ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ }
++
++ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
++ block_no);
++
++ retval = dev->drv.drv_check_bad_fn(dev, block_no);
++
++ if (retval== YAFFS_FAIL) {
++ yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
++
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ *seq_number = 0;
++ } else {
++ struct yaffs_ext_tags t;
++
++ yaffs_tags_marshall_read(dev,
++ block_no * dev->param.chunks_per_block,
++ NULL, &t);
++
++ if (t.chunk_used) {
++ *seq_number = t.seq_number;
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++ } else {
++ *seq_number = 0;
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "block query returns seq %d state %d",
++ *seq_number, *state);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ return dev->drv.drv_mark_bad_fn(dev, block_no);
++
++}
++
++
++void yaffs_tags_marshall_install(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
++
++ if (!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
++
++ if (!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
++
++ if (!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
++
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.10.40/fs/yaffs2/yaffs_tagsmarshall.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_tagsmarshall.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSMARSHALL_H__
++#define __YAFFS_TAGSMARSHALL_H__
++
++#include "yaffs_guts.h"
++void yaffs_tags_marshall_install(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_trace.h linux-3.10.40/fs/yaffs2/yaffs_trace.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_trace.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_trace_mask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS 0x00000002
++#define YAFFS_TRACE_ALLOCATE 0x00000004
++#define YAFFS_TRACE_SCAN 0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
++#define YAFFS_TRACE_ERASE 0x00000020
++#define YAFFS_TRACE_GC 0x00000040
++#define YAFFS_TRACE_WRITE 0x00000080
++#define YAFFS_TRACE_TRACING 0x00000100
++#define YAFFS_TRACE_DELETION 0x00000200
++#define YAFFS_TRACE_BUFFERS 0x00000400
++#define YAFFS_TRACE_NANDACCESS 0x00000800
++#define YAFFS_TRACE_GC_DETAIL 0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
++#define YAFFS_TRACE_MTD 0x00004000
++#define YAFFS_TRACE_CHECKPOINT 0x00008000
++
++#define YAFFS_TRACE_VERIFY 0x00010000
++#define YAFFS_TRACE_VERIFY_NAND 0x00020000
++#define YAFFS_TRACE_VERIFY_FULL 0x00040000
++#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
++
++#define YAFFS_TRACE_SYNC 0x00100000
++#define YAFFS_TRACE_BACKGROUND 0x00200000
++#define YAFFS_TRACE_LOCK 0x00400000
++#define YAFFS_TRACE_MOUNT 0x00800000
++
++#define YAFFS_TRACE_ERROR 0x40000000
++#define YAFFS_TRACE_BUG 0x80000000
++#define YAFFS_TRACE_ALWAYS 0xf0000000
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_verify.c linux-3.10.40/fs/yaffs2/yaffs_verify.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_verify.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,529 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_verify.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++
++int yaffs_skip_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask &
++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_full_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char * const block_state_name[] = {
++ "Unknown",
++ "Needs scan",
++ "Scanning",
++ "Empty",
++ "Allocating",
++ "Full",
++ "Dirty",
++ "Checkpoint",
++ "Collecting",
++ "Dead"
++};
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
++{
++ int actually_used;
++ int in_use;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Report illegal runtime states */
++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has undefined state %d",
++ n, bi->block_state);
++
++ switch (bi->block_state) {
++ case YAFFS_BLOCK_STATE_UNKNOWN:
++ case YAFFS_BLOCK_STATE_SCANNING:
++ case YAFFS_BLOCK_STATE_NEEDS_SCAN:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has bad run-state %s",
++ n, block_state_name[bi->block_state]);
++ }
++
++ /* Check pages in use and soft deletions are legal */
++
++ actually_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->pages_in_use < 0 ||
++ bi->pages_in_use > dev->param.chunks_per_block ||
++ bi->soft_del_pages < 0 ||
++ bi->soft_del_pages > dev->param.chunks_per_block ||
++ actually_used < 0 || actually_used > dev->param.chunks_per_block)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has illegal values pages_in_used %d soft_del_pages %d",
++ n, bi->pages_in_use, bi->soft_del_pages);
++
++ /* Check chunk bitmap legal */
++ in_use = yaffs_count_chunk_bits(dev, n);
++ if (in_use != bi->pages_in_use)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
++ n, bi->pages_in_use, in_use);
++}
++
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n)
++{
++ yaffs_verify_blk(dev, bi, n);
++
++ /* After collection the block should be in the erased state */
++
++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Block %d is in state %d after gc, should be erased",
++ n, bi->block_state);
++ }
++}
++
++void yaffs_verify_blocks(struct yaffs_dev *dev)
++{
++ int i;
++ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
++ int illegal_states = 0;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ memset(state_count, 0, sizeof(state_count));
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ yaffs_verify_blk(dev, bi, i);
++
++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
++ state_count[bi->block_state]++;
++ else
++ illegal_states++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
++
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%d blocks have illegal states",
++ illegal_states);
++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many allocating blocks");
++
++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%s %d blocks",
++ block_state_name[i], state_count[i]);
++
++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Checkpoint block count wrong dev %d count %d",
++ dev->blocks_in_checkpt,
++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
++
++ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Erased block count wrong dev %d count %d",
++ dev->n_erased_blocks,
++ state_count[YAFFS_BLOCK_STATE_EMPTY]);
++
++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many collecting blocks %d (max is 1)",
++ state_count[YAFFS_BLOCK_STATE_COLLECTING]);
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in
++ * which case those tests will not be performed.
++ */
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!(tags && obj && oh)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Verifying object header tags %p obj %p oh %p",
++ tags, obj, oh);
++ return;
++ }
++
++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++ oh->type > YAFFS_OBJECT_TYPE_MAX)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header type is illegal value 0x%x",
++ tags->obj_id, oh->type);
++
++ if (tags->obj_id != obj->obj_id)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch obj_id %d",
++ tags->obj_id, obj->obj_id);
++
++ /*
++ * Check that the object's parent ids match if parent_check requested.
++ *
++ * Tests do not apply to the root object.
++ */
++
++ if (parent_check && tags->obj_id > 1 && !obj->parent)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d obj->parent is NULL",
++ tags->obj_id, oh->parent_obj_id);
++
++ if (parent_check && obj->parent &&
++ oh->parent_obj_id != obj->parent->obj_id &&
++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d parent_obj_id %d",
++ tags->obj_id, oh->parent_obj_id,
++ obj->parent->obj_id);
++
++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is NULL",
++ obj->obj_id);
++
++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is 0xff",
++ obj->obj_id);
++}
++
++void yaffs_verify_file(struct yaffs_obj *obj)
++{
++ u32 x;
++ int required_depth;
++ int actual_depth;
++ int last_chunk;
++ u32 offset_in_chunk;
++ u32 the_chunk;
++
++ u32 i;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ struct yaffs_tnode *tn;
++ u32 obj_id;
++
++ if (!obj)
++ return;
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ dev = obj->my_dev;
++ obj_id = obj->obj_id;
++
++
++ /* Check file size is consistent with tnode depth */
++ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
++ &last_chunk, &offset_in_chunk);
++ last_chunk++;
++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x > 0) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ actual_depth = obj->variant.file_variant.top_level;
++
++ /* Check that the chunks in the tnode tree are all correct.
++ * We do this by scanning through the tnode tree and
++ * checking the tags for every chunk match.
++ */
++
++ if (yaffs_skip_nand_verification(dev))
++ return;
++
++ for (i = 1; i <= last_chunk; i++) {
++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
++
++ if (!tn)
++ continue;
++
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk > 0) {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ &tags);
++ if (tags.obj_id != obj_id || tags.chunk_id != i)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
++ obj_id, i, the_chunk,
++ tags.obj_id, tags.chunk_id);
++ }
++ }
++}
++
++void yaffs_verify_link(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify sane equivalent object */
++}
++
++void yaffs_verify_symlink(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify symlink string */
++}
++
++void yaffs_verify_special(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++}
++
++void yaffs_verify_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++ u32 chunk_min;
++ u32 chunk_max;
++ u32 chunk_id_ok;
++ u32 chunk_in_range;
++ u32 chunk_wrongly_deleted;
++ u32 chunk_valid;
++
++ if (!obj)
++ return;
++
++ if (obj->being_created)
++ return;
++
++ dev = obj->my_dev;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Check sane object header chunk */
++
++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
++ chunk_max =
++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
++
++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
++ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
++ chunk_valid = chunk_in_range &&
++ yaffs_check_chunk_bit(dev,
++ obj->hdr_chunk / dev->param.chunks_per_block,
++ obj->hdr_chunk % dev->param.chunks_per_block);
++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
++
++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has chunk_id %d %s %s",
++ obj->obj_id, obj->hdr_chunk,
++ chunk_id_ok ? "" : ",out of range",
++ chunk_wrongly_deleted ? ",marked as deleted" : "");
++
++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj_hdr *oh;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
++
++ yaffs_verify_oh(obj, oh, &tags, 1);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ /* Verify it has a parent */
++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has parent pointer %p which does not look like an object",
++ obj->obj_id, obj->parent);
++ }
++
++ /* Verify parent is a directory */
++ if (obj->parent &&
++ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d's parent is not a directory (type %d)",
++ obj->obj_id, obj->parent->variant_type);
++ }
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ yaffs_verify_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ yaffs_verify_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ yaffs_verify_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ yaffs_verify_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ yaffs_verify_special(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has illegaltype %d",
++ obj->obj_id, obj->variant_type);
++ break;
++ }
++}
++
++void yaffs_verify_objects(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int i;
++ struct list_head *lh;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Iterate through the objects in each hash entry */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ yaffs_verify_obj(obj);
++ }
++ }
++}
++
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++ int count = 0;
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!obj->parent) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
++ BUG();
++ return;
++ }
++
++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_verify_obj(list_obj);
++ if (obj == list_obj)
++ count++;
++ }
++
++ if (count != 1) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory %d times",
++ count);
++ BUG();
++ }
++}
++
++void yaffs_verify_dir(struct yaffs_obj *directory)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++
++ if (!directory) {
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_full_verification(directory->my_dev))
++ return;
++
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Directory has wrong type: %d",
++ directory->variant_type);
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &directory->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (list_obj->parent != directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory list has wrong parent %p",
++ list_obj->parent);
++ BUG();
++ }
++ yaffs_verify_obj_in_dir(list_obj);
++ }
++}
++
++static int yaffs_free_verification_failures;
++
++void yaffs_verify_free_chunks(struct yaffs_dev *dev)
++{
++ int counted;
++ int difference;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ counted = yaffs_count_free_chunks(dev);
++
++ difference = dev->n_free_chunks - counted;
++
++ if (difference) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Freechunks verification failure %d %d %d",
++ dev->n_free_chunks, counted, difference);
++ yaffs_free_verification_failures++;
++ }
++}
++
++int yaffs_verify_file_sane(struct yaffs_obj *in)
++{
++ (void) in;
++ return YAFFS_OK;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_verify.h linux-3.10.40/fs/yaffs2/yaffs_verify.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_verify.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_VERIFY_H__
++#define __YAFFS_VERIFY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
++ int n);
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n);
++void yaffs_verify_blocks(struct yaffs_dev *dev);
++
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check);
++void yaffs_verify_file(struct yaffs_obj *obj);
++void yaffs_verify_link(struct yaffs_obj *obj);
++void yaffs_verify_symlink(struct yaffs_obj *obj);
++void yaffs_verify_special(struct yaffs_obj *obj);
++void yaffs_verify_obj(struct yaffs_obj *obj);
++void yaffs_verify_objects(struct yaffs_dev *dev);
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
++void yaffs_verify_dir(struct yaffs_obj *directory);
++void yaffs_verify_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_verify_file_sane(struct yaffs_obj *obj);
++
++int yaffs_skip_verification(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_vfs.c linux-3.10.40/fs/yaffs2/yaffs_vfs.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_vfs.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,3600 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * 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 struct yaffs_dev associated with
++ * this superblock
++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
++ * superblock
++ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
++ */
++
++/*
++ * There are two variants of the VFS glue code. This variant should compile
++ * for any version of Linux.
++ */
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
++#define YAFFS_COMPILE_BACKGROUND
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
++#define YAFFS_COMPILE_FREEZER
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
++#define YAFFS_COMPILE_EXPORTFS
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_USE_SETATTR_COPY
++#define YAFFS_USE_TRUNCATE_SETSIZE
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_HAS_EVICT_INODE
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++#define YAFFS_NEW_FOLLOW_LINK 1
++#else
++#define YAFFS_NEW_FOLLOW_LINK 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_HAS_WRITE_SUPER
++#endif
++
++
++#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/fs.h>
++#include <linux/proc_fs.h>
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
++#include <linux/smp_lock.h>
++#endif
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++#include <linux/namei.h>
++#endif
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++#include <linux/exportfs.h>
++#endif
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#endif
++#ifdef YAFFS_COMPILE_FREEZER
++#include <linux/freezer.h>
++#endif
++
++#include <asm/div64.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/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, 26))
++#define YPROC_ROOT (&proc_root)
++#else
++#define YPROC_ROOT NULL
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define Y_INIT_TIMER(a) init_timer(a)
++#else
++#define Y_INIT_TIMER(a) init_timer_on_stack(a)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_SUPER_HAS_DIRTY
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++ uint64_t result = partition_size;
++ do_div(result, block_size);
++ return (uint32_t) result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/mtd/mtd.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#include "yaffs_linux.h"
++
++#include "yaffs_mtdif.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_getblockinfo.h"
++
++unsigned int yaffs_trace_mask =
++ YAFFS_TRACE_BAD_BLOCKS |
++ YAFFS_TRACE_ALWAYS |
++ 0;
++
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++unsigned int yaffs_gc_control = 1;
++unsigned int yaffs_bg_enable = 1;
++unsigned int yaffs_auto_select = 1;
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_trace_mask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++module_param(yaffs_gc_control, uint, 0644);
++module_param(yaffs_bg_enable, uint, 0644);
++#else
++MODULE_PARM(yaffs_trace_mask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++MODULE_PARM(yaffs_gc_control, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
++#else
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_inode_to_obj(iptr) \
++ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
++#else
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define Y_CLEAR_INODE(i) clear_inode(i)
++#else
++#define Y_CLEAR_INODE(i) end_writeback(i)
++#endif
++
++
++#define update_dir_time(dir) do {\
++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++ } while (0)
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj);
++
++
++static void yaffs_gross_lock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
++}
++
++static void yaffs_gross_unlock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
++}
++
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++ /* Lifted from jffs2 */
++
++ struct yaffs_obj *obj;
++ unsigned char *pg_buf;
++ int ret;
++ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readpage_nolock at %lld, size %08x",
++ (long long)pos,
++ (unsigned)PAGE_CACHE_SIZE);
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++#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_gross_lock(dev);
++
++ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
++
++ yaffs_gross_unlock(dev);
++
++ if (ret >= 0)
++ ret = 0;
++
++ if (ret) {
++ ClearPageUptodate(pg);
++ SetPageError(pg);
++ } else {
++ SetPageUptodate(pg);
++ ClearPageError(pg);
++ }
++
++ flush_dcache_page(pg);
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
++ 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)
++{
++ int ret;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
++ ret = yaffs_readpage_unlock(f, pg);
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
++ return ret;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
++#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
++#else
++#define YCRED_FSUID() YCRED(current)->fsuid
++#define YCRED_FSGID() YCRED(current)->fsgid
++
++static inline uid_t i_uid_read(const struct inode *inode)
++{
++ return inode->i_uid;
++}
++
++static inline gid_t i_gid_read(const struct inode *inode)
++{
++ return inode->i_gid;
++}
++
++static inline void i_uid_write(struct inode *inode, uid_t uid)
++{
++ inode->i_uid = uid;
++}
++
++static inline void i_gid_write(struct inode *inode, gid_t gid)
++{
++ inode->i_gid = gid;
++}
++#endif
++
++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc)
++ lc->dirty = val;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb)
++ sb->s_dirt = val;
++ }
++#endif
++
++}
++
++static void yaffs_set_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 1);
++}
++
++static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 0);
++}
++
++static int yaffs_check_super_dirty(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc && lc->dirty)
++ return 1;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb && sb->s_dirt)
++ return 1;
++ }
++#endif
++ return 0;
++
++}
++
++#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 yaffs_dev *dev;
++ struct address_space *mapping = page->mapping;
++ struct inode *inode;
++ unsigned long end_index;
++ char *buffer;
++ struct yaffs_obj *obj;
++ int n_written = 0;
++ unsigned n_bytes;
++ loff_t i_size;
++
++ if (!mapping)
++ BUG();
++ inode = mapping->host;
++ if (!inode)
++ BUG();
++ i_size = i_size_read(inode);
++
++ end_index = i_size >> PAGE_CACHE_SHIFT;
++
++ if (page->index < end_index)
++ n_bytes = PAGE_CACHE_SIZE;
++ else {
++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
++
++ if (page->index > end_index || !n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, inode size = %lld!!",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
++ inode->i_size);
++ yaffs_trace(YAFFS_TRACE_OS,
++ " -> don't care!!");
++
++ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ return 0;
++ }
++ }
++
++ if (n_bytes != PAGE_CACHE_SIZE)
++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
++
++ get_page(page);
++
++ buffer = kmap(page);
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, size %08x",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag0: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ n_written = yaffs_wr_file(obj, buffer,
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag1: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ yaffs_gross_unlock(dev);
++
++ kunmap(page);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ put_page(page);
++
++ return (n_written == n_bytes) ? 0 : -ENOSPC;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ int n_free_chunks;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ n_free_chunks = yaffs_get_n_free_chunks(dev);
++
++ yaffs_gross_unlock(dev);
++
++ return (n_free_chunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_gross_unlock(dev);
++}
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{
++ struct page *pg = NULL;
++ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++ int ret = 0;
++ int space_held = 0;
++
++ /* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++ pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++ pg = __grab_cache_page(mapping, index);
++#endif
++
++ *pagep = pg;
++ if (!pg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "start yaffs_write_begin index %d(%x) uptodate %d",
++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
++
++ /* Get fs space */
++ space_held = yaffs_hold_space(filp);
++
++ if (!space_held) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ /* Update page if required */
++
++ if (!Page_Uptodate(pg))
++ ret = yaffs_readpage_nolock(filp, pg);
++
++ if (ret)
++ goto out;
++
++ /* Happy path return */
++ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
++
++ return 0;
++
++out:
++ yaffs_trace(YAFFS_TRACE_OS,
++ "end yaffs_write_begin fail returning %d", ret);
++ if (space_held)
++ yaffs_release_space(filp);
++ if (pg) {
++ unlock_page(pg);
++ page_cache_release(pg);
++ }
++ return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to)
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
++
++ if (!Page_Uptodate(pg))
++ return yaffs_readpage_nolock(f, pg);
++ return 0;
++}
++#endif
++
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t * pos)
++{
++ struct yaffs_obj *obj;
++ int n_written;
++ loff_t ipos;
++ struct inode *inode;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: hey obj is null!");
++ return -EINVAL;
++ }
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
++ (unsigned)n, (unsigned)n, obj->obj_id, ipos);
++
++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: %d(%x) bytes written",
++ (unsigned)n, (unsigned)n);
++
++ if (n_written > 0) {
++ ipos += n_written;
++ *pos = ipos;
++ if (ipos > inode->i_size) {
++ inode->i_size = ipos;
++ inode->i_blocks = (ipos + 511) >> 9;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write size updated to %lld bytes, %d blocks",
++ ipos, (int)(inode->i_blocks));
++ }
++
++ }
++ yaffs_gross_unlock(dev);
++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
++}
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata)
++{
++ int ret = 0;
++ void *addr, *kva;
++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++ kva = kmap(pg);
++ addr = kva + offset_into_page;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end addr %p pos %lld n_bytes %d",
++ addr, pos, copied);
++
++ ret = yaffs_file_write(filp, addr, copied, &pos);
++
++ if (ret != copied) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end not same size ret %d copied %d",
++ ret, copied);
++ SetPageError(pg);
++ }
++
++ kunmap(pg);
++
++ yaffs_release_space(filp);
++ unlock_page(pg);
++ page_cache_release(pg);
++ return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to)
++{
++ void *addr, *kva;
++
++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++ int n_bytes = to - offset;
++ int n_written;
++
++ kva = kmap(pg);
++ addr = kva + offset;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write addr %p pos %lld n_bytes %d",
++ addr, pos, n_bytes);
++
++ n_written = yaffs_file_write(f, addr, n_bytes, &pos);
++
++ if (n_written != n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write not same size n_written %d n_bytes %d",
++ n_written, n_bytes);
++ SetPageError(pg);
++ }
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write returning %d",
++ n_written == n_bytes ? 0 : n_written);
++
++ return n_written == n_bytes ? 0 : n_written;
++}
++#endif
++
++static struct address_space_operations yaffs_file_address_operations = {
++ .readpage = yaffs_readpage,
++ .writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++ .write_begin = yaffs_write_begin,
++ .write_end = yaffs_write_end,
++#else
++ .prepare_write = yaffs_prepare_write,
++ .commit_write = yaffs_commit_write,
++#endif
++};
++
++
++#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
++{
++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_flush object %d (%s)",
++ obj->obj_id,
++ obj->dirty ? "dirty" : "clean");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_file(obj, 1, 0);
++
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync)
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync)
++#endif
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++ struct dentry *dentry = file->f_path.dentry;
++#endif
++
++ obj = yaffs_dentry_to_obj(dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_object");
++ yaffs_gross_lock(dev);
++ yaffs_flush_file(obj, 1, datasync);
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const 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,
++ .llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const 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 const 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
++
++
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++ void *kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + start, 0, end - start);
++ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(page);
++}
++#endif
++
++
++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
++{
++#ifdef YAFFS_USE_TRUNCATE_SETSIZE
++ truncate_setsize(inode, newsize);
++ return 0;
++#else
++ truncate_inode_pages(&inode->i_data, newsize);
++ return 0;
++#endif
++
++}
++
++
++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
++{
++#ifdef YAFFS_USE_SETATTR_COPY
++ setattr_copy(inode, attr);
++ return 0;
++#else
++ return inode_setattr(inode, attr);
++#endif
++
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_setattr of object %d",
++ yaffs_inode_to_obj(inode)->obj_id);
++#if 0
++ /* Fail if a requested resize >= 2GB */
++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
++ error = -EINVAL;
++#endif
++
++ if (error == 0)
++ error = inode_change_ok(inode, attr);
++ if (error == 0) {
++ int result;
++ if (!error) {
++ error = yaffs_vfs_setattr(inode, attr);
++ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_vfs_setsize(inode, attr->ia_size);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++ }
++ }
++ dev = yaffs_inode_to_obj(inode)->my_dev;
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "resize to %d(%x)",
++ (int)(attr->ia_size),
++ (int)(attr->ia_size));
++ }
++ yaffs_gross_lock(dev);
++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
++ if (result == YAFFS_OK) {
++ error = 0;
++ } else {
++ error = -EPERM;
++ }
++ yaffs_gross_unlock(dev);
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_set_xattrib(obj, name, value, size, flags);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
++ void *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_getxattr \"%s\" from object %d",
++ name, obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_get_xattrib(obj, name, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_removexattr(struct dentry *dentry, const char *name)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_remove_xattrib(obj, name);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_list_xattrib(obj, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr done returning %d", error);
++
++ return error;
++}
++
++
++static const struct inode_operations yaffs_file_inode_operations = {
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++ int buflen)
++{
++ unsigned char *alias;
++ int ret;
++
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++
++ yaffs_gross_unlock(dev);
++
++ if (!alias)
++ return -ENOMEM;
++
++ ret = vfs_readlink(dentry, buffer, buflen, alias);
++ kfree(alias);
++ return ret;
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ void *ret;
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int ret
++#endif
++ unsigned char *alias;
++ int ret_int = 0;
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++ yaffs_gross_unlock(dev);
++
++ if (!alias) {
++ ret_int = -ENOMEM;
++ goto out;
++ }
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ nd_set_link(nd, alias);
++ ret = alias;
++out:
++ if (ret_int)
++ ret = ERR_PTR(ret_int);
++ return ret;
++#else
++ ret = vfs_follow_link(nd, alias);
++ kfree(alias);
++out:
++ if (ret_int)
++ ret = ret_int;
++ return ret;
++#endif
++}
++
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* 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)
++{
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_put_inode: ino %d, count %d"),
++ (int)inode->i_ino, atomic_read(&inode->i_count);
++
++}
++#endif
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++{
++ kfree(alias);
++}
++#endif
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++ .readlink = yaffs_readlink,
++ .follow_link = yaffs_follow_link,
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ .put_link = yaffs_put_link,
++#endif
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++ struct inode *inode;
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return 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_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ yaffs_gross_unlock(dev);
++
++ unlock_new_inode(inode);
++ return inode;
++}
++
++#else
++
++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.
++ */
++
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_inode for %d", (int)inode->i_ino);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++}
++
++#endif
++
++
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ struct yaffs_obj *obj)
++{
++ struct inode *inode;
++
++ if (!sb) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL super_block!!");
++ return NULL;
++
++ }
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL object!!");
++ return NULL;
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for object %d", obj->obj_id);
++
++ inode = Y_IGET(sb, obj->obj_id);
++ if (IS_ERR(inode))
++ return NULL;
++
++ /* NB Side effect: iget calls back to yaffs_read_inode(). */
++ /* iget also increments the inode's i_count */
++ /* NB You can't be holding gross_lock or deadlock will happen! */
++
++ return inode;
++}
++
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++ dev_t rdev)
++#elif (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;
++
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_dev *dev;
++
++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
++
++ int error = -ENOSPC;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++ mode |= S_ISGID;
++
++ if (parent) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: parent object %d type %d",
++ parent->obj_id, parent->variant_type);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: could not get parent object");
++ return -EPERM;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: making oject for %s, mode %x dev %x",
++ dentry->d_name.name, mode, rdev);
++
++ dev = parent->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ switch (mode & S_IFMT) {
++ default:
++ /* Special (socket, fifo, device...) */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, old_encode_dev(rdev));
++#else
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, rdev);
++#endif
++ break;
++ case S_IFREG: /* file */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
++ gid);
++ break;
++ case S_IFDIR: /* directory */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
++ uid, gid);
++ break;
++ case S_IFLNK: /* symlink */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
++ obj = NULL; /* Do we ever get here? */
++ break;
++ }
++
++ /* Can not call yaffs_get_inode() with gross lock held */
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod created object %d count = %d",
++ obj->obj_id, atomic_read(&inode->i_count));
++ error = 0;
++ yaffs_fill_inode_from_obj(dir, parent);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
++ error = -ENOMEM;
++ }
++
++ return error;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++#else
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++ int ret_val;
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++ return ret_val;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ bool dummy)
++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ struct nameidata *n)
++#elif (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
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ unsigned int dummy)
++#elif (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
++{
++ struct yaffs_obj *obj;
++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
++
++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
++
++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
++
++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
++
++ /* Can't hold gross lock when calling yaffs_get_inode() */
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_lookup found %d", obj->obj_id);
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
++
++ }
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *link = NULL;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
++ link =
++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ obj);
++
++ if (link) {
++ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
++ d_instantiate(dentry, old_dentry->d_inode);
++ atomic_inc(&old_dentry->d_inode->i_count);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_link link count %d i_count %d",
++ old_dentry->d_inode->i_nlink,
++ atomic_read(&old_dentry->d_inode->i_count));
++ }
++
++ yaffs_gross_unlock(dev);
++
++ if (link) {
++ update_dir_time(dir);
++ return 0;
++ }
++
++ return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
++
++ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ return -ENAMETOOLONG;
++
++ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
++ YAFFS_MAX_ALIAS_LENGTH)
++ return -ENAMETOOLONG;
++
++ dev = yaffs_inode_to_obj(dir)->my_dev;
++ yaffs_gross_lock(dev);
++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ S_IFLNK | S_IRWXUGO, uid, gid, symname);
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ struct inode *inode;
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
++ return 0;
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
++ }
++
++ return -ENOMEM;
++}
++
++/*
++ * 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)
++{
++ struct yaffs_dev *dev;
++ int ret_val = YAFFS_FAIL;
++ struct yaffs_obj *target;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
++ dev = yaffs_inode_to_obj(old_dir)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ /* Check if the target is an existing directory that is not empty. */
++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++
++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !list_empty(&target->variant.dir_variant.children)) {
++
++ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
++
++ ret_val = YAFFS_FAIL;
++ } else {
++ /* Now does unlinking internally using shadowing mechanism */
++ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
++
++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
++ old_dentry->d_name.name,
++ yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++ }
++ yaffs_gross_unlock(dev);
++
++ if (ret_val == YAFFS_OK) {
++ if (target)
++ inode_dec_link_count(new_dentry->d_inode);
++
++ update_dir_time(old_dir);
++ if (old_dir != new_dir)
++ update_dir_time(new_dir);
++ return 0;
++ } else {
++ return -ENOTEMPTY;
++ }
++}
++
++
++
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int ret_val;
++
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
++ (int)(dir->i_ino), dentry->d_name.name);
++ obj = yaffs_inode_to_obj(dir);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ ret_val = yaffs_unlinker(obj, dentry->d_name.name);
++
++ if (ret_val == YAFFS_OK) {
++ inode_dec_link_count(dentry->d_inode);
++ dir->i_version++;
++ yaffs_gross_unlock(dev);
++ update_dir_time(dir);
++ return 0;
++ }
++ yaffs_gross_unlock(dev);
++ return -ENOTEMPTY;
++}
++
++
++
++static const 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,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the remove_obj_fn to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each struct yaffs_dev has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_search_context {
++ struct yaffs_dev *dev;
++ struct yaffs_obj *dir_obj;
++ struct yaffs_obj *next_return;
++ struct list_head others;
++};
++
++/*
++ * yaffs_new_search() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
++{
++ struct yaffs_dev *dev = dir->my_dev;
++ struct yaffs_search_context *sc =
++ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
++ if (sc) {
++ sc->dir_obj = dir;
++ sc->dev = dev;
++ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else
++ sc->next_return =
++ list_entry(dir->variant.dir_variant.children.next,
++ struct yaffs_obj, siblings);
++ INIT_LIST_HEAD(&sc->others);
++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
++ }
++ return sc;
++}
++
++/*
++ * yaffs_search_end() disposes of a search context and cleans up.
++ */
++static void yaffs_search_end(struct yaffs_search_context *sc)
++{
++ if (sc) {
++ list_del(&sc->others);
++ kfree(sc);
++ }
++}
++
++/*
++ * yaffs_search_advance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_search_advance(struct yaffs_search_context *sc)
++{
++ if (!sc)
++ return;
++
++ if (sc->next_return == NULL ||
++ list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else {
++ struct list_head *next = sc->next_return->siblings.next;
++
++ if (next == &sc->dir_obj->variant.dir_variant.children)
++ sc->next_return = NULL; /* end of list */
++ else
++ sc->next_return =
++ list_entry(next, struct yaffs_obj, siblings);
++ }
++}
++
++/*
++ * yaffs_remove_obj_callback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
++{
++
++ struct list_head *i;
++ struct yaffs_search_context *sc;
++ struct list_head *search_contexts =
++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
++
++ /* Iterate through the directory search contexts.
++ * If any are currently on the object being removed, then advance
++ * the search context to the next object to prevent a hanging pointer.
++ */
++ list_for_each(i, search_contexts) {
++ sc = list_entry(i, struct yaffs_search_context, others);
++ if (sc->next_return == obj)
++ yaffs_search_advance(sc);
++ }
++
++}
++
++
++/*-----------------------------------------------------------------*/
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++static int yaffs_readdir(struct file *file, struct dir_context *ctx)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = file->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(file->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = ctx->pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)file->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dotdot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++
++ curoffs = 1;
++
++ /* If the directory has changed since the open or last call to
++ readdir, rewind to after the 2 canned entries. */
++ if (file->f_version != inode->i_version) {
++ offset = 2;
++ ctx->pos = offset;
++ file->f_version = inode->i_version;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (!dir_emit(ctx, name, strlen(name),
++ this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ ctx->pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#else
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = f->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = f->f_pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ f->f_pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)f->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, "..", 2, offset,
++ f->f_dentry->d_parent->d_inode->i_ino,
++ DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ 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;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (filldir(dirent,
++ name,
++ strlen(name),
++ offset, this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ f->f_pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#endif
++
++static const struct file_operations yaffs_dir_operations = {
++ .read = generic_read_dir,
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++ .iterate = yaffs_readdir,
++#else
++ .readdir = yaffs_readdir,
++#endif
++ .fsync = yaffs_sync_object,
++ .llseek = generic_file_llseek,
++};
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj)
++{
++ if (inode && obj) {
++
++ /* Check mode against the variant type and attempt to repair if broken. */
++ u32 mode = obj->yst_mode;
++ switch (obj->variant_type) {
++ 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_flags |= S_NOATIME;
++
++ inode->i_ino = obj->obj_id;
++ inode->i_mode = obj->yst_mode;
++ i_uid_write(inode, obj->yst_uid);
++ i_gid_write(inode, 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_get_obj_length(obj);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++
++ set_nlink(inode, yaffs_get_obj_link_count(obj));
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
++ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
++ 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_inode_to_obj_lv(inode) = obj;
++
++ obj->my_inode = inode;
++
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode invalid parameters");
++ }
++
++}
++
++
++
++/*
++ * yaffs background thread functions .
++ * yaffs_bg_thread_fn() the thread function
++ * yaffs_bg_start() launches the background thread.
++ * yaffs_bg_stop() cleans up the background thread.
++ *
++ * NB:
++ * The thread should only run after the yaffs is initialised
++ * The thread should be stopped before yaffs is unmounted.
++ * The thread should not do any writing while the fs is in read only.
++ */
++
++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
++{
++ unsigned erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned scattered = 0; /* Free chunks not in an erased block */
++
++ if (erased_chunks < dev->n_free_chunks)
++ scattered = (dev->n_free_chunks - erased_chunks);
++
++ if (!context->bg_running)
++ return 0;
++ else if (scattered < (dev->param.chunks_per_block * 2))
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 2)
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 4)
++ return 1;
++ else
++ return 2;
++}
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++
++void yaffs_background_waker(unsigned long data)
++{
++ wake_up_process((struct task_struct *)data);
++}
++
++static int yaffs_bg_thread_fn(void *data)
++{
++ struct yaffs_dev *dev = (struct yaffs_dev *)data;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned long now = jiffies;
++ unsigned long next_dir_update = now;
++ unsigned long next_gc = now;
++ unsigned long expires;
++ unsigned int urgency;
++
++ int gc_result;
++ struct timer_list timer;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "yaffs_background starting for dev %p", (void *)dev);
++
++#ifdef YAFFS_COMPILE_FREEZER
++ set_freezable();
++#endif
++ while (context->bg_running) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
++
++ if (kthread_should_stop())
++ break;
++
++#ifdef YAFFS_COMPILE_FREEZER
++ if (try_to_freeze())
++ continue;
++#endif
++ yaffs_gross_lock(dev);
++
++ now = jiffies;
++
++ if (time_after(now, next_dir_update) && yaffs_bg_enable) {
++ yaffs_update_dirty_dirs(dev);
++ next_dir_update = now + HZ;
++ }
++
++ if (time_after(now, next_gc) && yaffs_bg_enable) {
++ if (!dev->is_checkpointed) {
++ urgency = yaffs_bg_gc_urgency(dev);
++ gc_result = yaffs_bg_gc(dev, urgency);
++ if (urgency > 1)
++ next_gc = now + HZ / 20 + 1;
++ else if (urgency > 0)
++ next_gc = now + HZ / 10 + 1;
++ else
++ next_gc = now + HZ * 2;
++ } else {
++ /*
++ * gc not running so set to next_dir_update
++ * to cut down on wake ups
++ */
++ next_gc = next_dir_update;
++ }
++ }
++ yaffs_gross_unlock(dev);
++#if 1
++ expires = next_dir_update;
++ if (time_before(next_gc, expires))
++ expires = next_gc;
++ if (time_before(expires, now))
++ expires = now + HZ;
++
++ Y_INIT_TIMER(&timer);
++ timer.expires = expires + 1;
++ timer.data = (unsigned long)current;
++ timer.function = yaffs_background_waker;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_timer(&timer);
++ schedule();
++ del_timer_sync(&timer);
++#else
++ msleep(10);
++#endif
++ }
++
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ int retval = 0;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++
++ if (dev->read_only)
++ return -1;
++
++ context->bg_running = 1;
++
++ context->bg_thread = kthread_run(yaffs_bg_thread_fn,
++ (void *)dev, "yaffs-bg-%d",
++ context->mount_id);
++
++ if (IS_ERR(context->bg_thread)) {
++ retval = PTR_ERR(context->bg_thread);
++ context->bg_thread = NULL;
++ context->bg_running = 0;
++ }
++ return retval;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
++
++ ctxt->bg_running = 0;
++
++ if (ctxt->bg_thread) {
++ kthread_stop(ctxt->bg_thread);
++ ctxt->bg_thread = NULL;
++ }
++}
++#else
++static int yaffs_bg_thread_fn(void *data)
++{
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ return 0;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++}
++#endif
++
++
++static void yaffs_flush_inodes(struct super_block *sb)
++{
++ struct inode *iptr;
++ struct yaffs_obj *obj;
++
++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
++ obj = yaffs_inode_to_obj(iptr);
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "flushing obj %d",
++ obj->obj_id);
++ yaffs_flush_file(obj, 1, 0);
++ }
++ }
++}
++
++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ if (!dev)
++ return;
++
++ yaffs_flush_inodes(sb);
++ yaffs_update_dirty_dirs(dev);
++ yaffs_flush_whole_cache(dev);
++ if (do_checkpoint)
++ yaffs_checkpoint_save(dev);
++}
++
++static LIST_HEAD(yaffs_context_list);
++struct mutex yaffs_context_lock;
++
++static void yaffs_put_super(struct super_block *sb)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super");
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "Shutting down yaffs background thread");
++ yaffs_bg_stop(dev);
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "yaffs background thread shut down");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_super(sb, 1);
++
++ yaffs_deinitialise(dev);
++
++ yaffs_gross_unlock(dev);
++
++ mutex_lock(&yaffs_context_lock);
++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
++ mutex_unlock(&yaffs_context_lock);
++
++ if (yaffs_dev_to_lc(dev)->spare_buffer) {
++ kfree(yaffs_dev_to_lc(dev)->spare_buffer);
++ yaffs_dev_to_lc(dev)->spare_buffer = NULL;
++ }
++
++ kfree(dev);
++
++ yaffs_put_mtd_device(mtd);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super done");
++}
++
++
++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
++{
++ return yaffs_gc_control;
++}
++
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++
++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
++ uint32_t generation)
++{
++ return Y_IGET(sb, ino);
++}
++
++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++struct dentry *yaffs2_get_parent(struct dentry *dentry)
++{
++
++ struct super_block *sb = dentry->d_inode->i_sb;
++ struct dentry *parent = ERR_PTR(-ENOENT);
++ struct inode *inode;
++ unsigned long parent_ino;
++ struct yaffs_obj *d_obj;
++ struct yaffs_obj *parent_obj;
++
++ d_obj = yaffs_inode_to_obj(dentry->d_inode);
++
++ if (d_obj) {
++ parent_obj = d_obj->parent;
++ if (parent_obj) {
++ parent_ino = yaffs_get_obj_inode(parent_obj);
++ inode = Y_IGET(sb, parent_ino);
++
++ if (IS_ERR(inode)) {
++ parent = ERR_CAST(inode);
++ } else {
++ parent = d_obtain_alias(inode);
++ if (!IS_ERR(parent)) {
++ parent = ERR_PTR(-ENOMEM);
++ iput(inode);
++ }
++ }
++ }
++ }
++
++ return parent;
++}
++
++/* Just declare a zero structure as a NULL value implies
++ * using the default functions of exportfs.
++ */
++
++static struct export_operations yaffs_export_ops = {
++ .fh_to_dentry = yaffs2_fh_to_dentry,
++ .fh_to_parent = yaffs2_fh_to_parent,
++ .get_parent = yaffs2_get_parent,
++};
++
++#endif
++
++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
++{
++ /* Clear the association between the inode and
++ * the struct yaffs_obj.
++ */
++ obj->my_inode = NULL;
++ yaffs_inode_to_obj_lv(inode) = NULL;
++
++ /* If the object freeing was deferred, then the real
++ * free happens now.
++ * This should fix the inode inconsistency problem.
++ */
++ yaffs_handle_defered_free(obj);
++}
++
++#ifdef YAFFS_HAS_EVICT_INODE
++/* yaffs_evict_inode combines into one operation what was previously done in
++ * yaffs_clear_inode() and yaffs_delete_inode()
++ *
++ */
++static void yaffs_evict_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ int deleteme = 0;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_evict_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (!inode->i_nlink && !is_bad_inode(inode))
++ deleteme = 1;
++ truncate_inode_pages(&inode->i_data, 0);
++ Y_CLEAR_INODE(inode);
++
++ if (deleteme && obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(dev);
++ }
++}
++#else
++
++/* clear is called to tell the fs to release any per-inode data it holds.
++ * The object might still exist on disk and is just being thrown out of the cache
++ * or else the object has actually been deleted and we're being called via
++ * the chain
++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
++ */
++
++static void yaffs_clear_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_clear_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(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)
++{
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_delete_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ truncate_inode_pages(&inode->i_data, 0);
++#endif
++ clear_inode(inode);
++}
++#endif
++
++
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++ 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)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#endif
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
++
++ yaffs_gross_lock(dev);
++
++ buf->f_type = YAFFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_namelen = 255;
++
++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
++ /* Do this if chunk size is not a power of 2 */
++
++ uint64_t bytes_in_dev;
++ uint64_t bytes_free;
++
++ bytes_in_dev =
++ ((uint64_t)
++ ((dev->param.end_block - dev->param.start_block +
++ 1))) * ((uint64_t) (dev->param.chunks_per_block *
++ dev->data_bytes_per_chunk));
++
++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
++ buf->f_blocks = bytes_in_dev;
++
++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
++ ((uint64_t) (dev->data_bytes_per_chunk));
++
++ do_div(bytes_free, sb->s_blocksize);
++
++ buf->f_bfree = bytes_free;
++
++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
++
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ } else {
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++ }
++
++ buf->f_files = 0;
++ buf->f_ffree = 0;
++ buf->f_bavail = buf->f_bfree;
++
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++
++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
++{
++
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
++ int do_checkpoint;
++ int dirty = yaffs_check_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
++ gc_urgent,
++ dirty ? "dirty" : "clean",
++ request_checkpoint ? "checkpoint requested" : "no checkpoint",
++ oneshot_checkpoint ? " one-shot" : "");
++
++ yaffs_gross_lock(dev);
++ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
++ oneshot_checkpoint) && !dev->is_checkpointed;
++
++ if (dirty || do_checkpoint) {
++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
++ yaffs_clear_super_dirty(dev);
++ if (oneshot_checkpoint)
++ yaffs_auto_checkpoint &= ~4;
++ }
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#ifdef YAFFS_HAS_WRITE_SUPER
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_write_super %s",
++ request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++ return 0;
++#endif
++}
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++ return 0;
++}
++
++
++
++static const struct super_operations yaffs_super_ops = {
++ .statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++ .read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++ .put_inode = yaffs_put_inode,
++#endif
++ .put_super = yaffs_put_super,
++#ifdef YAFFS_HAS_EVICT_INODE
++ .evict_inode = yaffs_evict_inode,
++#else
++ .delete_inode = yaffs_delete_inode,
++ .clear_inode = yaffs_clear_inode,
++#endif
++ .sync_fs = yaffs_sync_fs,
++#ifdef YAFFS_HAS_WRITE_SUPER
++ .write_super = yaffs_write_super,
++#endif
++};
++
++struct yaffs_options {
++ int inband_tags;
++ int skip_checkpoint_read;
++ int skip_checkpoint_write;
++ int no_cache;
++ int tags_ecc_on;
++ int tags_ecc_overridden;
++ int lazy_loading_enabled;
++ int lazy_loading_overridden;
++ int empty_lost_and_found;
++ int empty_lost_and_found_overridden;
++ int disable_summary;
++};
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(struct 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++;
++
++ 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, "tags-ecc-off")) {
++ options->tags_ecc_on = 0;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "tags-ecc-on")) {
++ options->tags_ecc_on = 1;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-off")) {
++ options->lazy_loading_enabled = 0;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-on")) {
++ options->lazy_loading_enabled = 1;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "disable-summary")) {
++ options->disable_summary = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
++ options->empty_lost_and_found = 0;
++ options->empty_lost_and_found_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
++ options->empty_lost_and_found = 1;
++ options->empty_lost_and_found_overridden = 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 dentry *yaffs_make_root(struct inode *inode)
++{
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++ struct dentry *root = d_alloc_root(inode);
++
++ if (!root)
++ iput(inode);
++
++ return root;
++#else
++ return d_make_root(inode);
++#endif
++}
++
++
++
++
++static struct super_block *yaffs_internal_read_super(int yaffs_version,
++ struct super_block *sb,
++ void *data, int silent)
++{
++ int n_blocks;
++ struct inode *inode = NULL;
++ struct dentry *root;
++ struct yaffs_dev *dev = 0;
++ char devname_buf[BDEVNAME_SIZE + 1];
++ struct mtd_info *mtd;
++ int err;
++ char *data_str = (char *)data;
++ struct yaffs_linux_context *context = NULL;
++ struct yaffs_param *param;
++
++ int read_only = 0;
++ int inband_tags = 0;
++
++ struct yaffs_options options;
++
++ unsigned mount_id;
++ int found;
++ struct yaffs_linux_context *context_iterator;
++ struct list_head *l;
++
++ if (!sb) {
++ printk(KERN_INFO "yaffs: sb is NULL\n");
++ return NULL;
++ }
++
++ sb->s_magic = YAFFS_MAGIC;
++ sb->s_op = &yaffs_super_ops;
++ sb->s_flags |= MS_NOATIME;
++
++ read_only = ((sb->s_flags & MS_RDONLY) != 0);
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++ sb->s_export_op = &yaffs_export_ops;
++#endif
++
++ 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\" %s\n",
++ sb->s_dev,
++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
++
++ 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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: Using yaffs%d", yaffs_version);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
++ MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ yaffs_devname(sb, devname_buf));
++
++ /* Get the device */
++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++ if (IS_ERR(mtd)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device %u either not valid or unavailable",
++ MINOR(sb->s_dev));
++ return NULL;
++ }
++
++ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
++ yaffs_version = 2;
++ }
++
++ /* Added NCB 26/5/2006 for completeness */
++ if (yaffs_version == 2 && !options.inband_tags
++ && WRITE_SIZE(mtd) == 512) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
++ yaffs_version = 1;
++ }
++
++ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
++ options.inband_tags)
++ inband_tags = 1;
++
++ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++ 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 struct yaffs_dev up for mtd
++ */
++
++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++ read_only = 1;
++ printk(KERN_INFO
++ "yaffs: mtd is read only, setting superblock read only\n"
++ );
++ sb->s_flags |= MS_RDONLY;
++ }
++
++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
++
++ if (!dev || !context) {
++ kfree(dev);
++ kfree(context);
++ dev = NULL;
++ context = NULL;
++
++ /* Deep shit could not allocate device structure */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
++ );
++ return NULL;
++ }
++ memset(dev, 0, sizeof(struct yaffs_dev));
++ param = &(dev->param);
++
++ memset(context, 0, sizeof(struct yaffs_linux_context));
++ dev->os_context = context;
++ INIT_LIST_HEAD(&(context->context_list));
++ context->dev = dev;
++ context->super = sb;
++
++ dev->read_only = read_only;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ sb->s_fs_info = dev;
++#else
++ sb->u.generic_sbp = dev;
++#endif
++
++
++ dev->driver_context = mtd;
++ param->name = mtd->name;
++
++ /* Set up the memory size parameters.... */
++
++
++ param->n_reserved_blocks = 5;
++ param->n_caches = (options.no_cache) ? 0 : 10;
++ param->inband_tags = inband_tags;
++
++ param->enable_xattr = 1;
++ if (options.lazy_loading_overridden)
++ param->disable_lazy_load = !options.lazy_loading_enabled;
++
++ param->defered_dir_update = 1;
++
++ if (options.tags_ecc_overridden)
++ param->no_tags_ecc = !options.tags_ecc_on;
++
++ param->empty_lost_n_found = 1;
++ param->refresh_period = 500;
++ param->disable_summary = options.disable_summary;
++
++
++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
++ param->disable_bad_block_marking = 1;
++#endif
++ if (options.empty_lost_and_found_overridden)
++ param->empty_lost_n_found = options.empty_lost_and_found;
++
++ /* ... and the functions. */
++ if (yaffs_version == 2) {
++ param->is_yaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ param->total_bytes_per_chunk = mtd->writesize;
++ param->chunks_per_block = mtd->erasesize / mtd->writesize;
++#else
++ param->total_bytes_per_chunk = mtd->oobblock;
++ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
++#endif
++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++ } else {
++ param->is_yaffs2 = 0;
++ n_blocks = YCALCBLOCKS(mtd->size,
++ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
++
++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
++ }
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++
++ yaffs_mtd_drv_install(dev);
++
++ param->sb_dirty_fn = yaffs_set_super_dirty;
++ param->gc_control_fn = yaffs_gc_control_callback;
++
++ yaffs_dev_to_lc(dev)->super = sb;
++
++ param->use_nand_ecc = 1;
++
++ param->skip_checkpt_rd = options.skip_checkpoint_read;
++ param->skip_checkpt_wr = options.skip_checkpoint_write;
++
++ mutex_lock(&yaffs_context_lock);
++ /* Get a mount id */
++ found = 0;
++ for (mount_id = 0; !found; mount_id++) {
++ found = 1;
++ list_for_each(l, &yaffs_context_list) {
++ context_iterator =
++ list_entry(l, struct yaffs_linux_context,
++ context_list);
++ if (context_iterator->mount_id == mount_id)
++ found = 0;
++ }
++ }
++ context->mount_id = mount_id;
++
++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
++ &yaffs_context_list);
++ mutex_unlock(&yaffs_context_lock);
++
++ /* Directory search handling... */
++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
++ param->remove_obj_fn = yaffs_remove_obj_callback;
++
++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
++
++ yaffs_gross_lock(dev);
++
++ err = yaffs_guts_initialise(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: guts initialised %s",
++ (err == YAFFS_OK) ? "OK" : "FAILED");
++
++ if (err == YAFFS_OK)
++ yaffs_bg_start(dev);
++
++ if (!context->bg_thread)
++ param->defered_dir_update = 0;
++
++ sb->s_maxbytes = yaffs_max_file_size(dev);
++
++ /* Release lock before yaffs_get_inode() */
++ yaffs_gross_unlock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
++
++ root = yaffs_make_root(inode);
++
++ if (!root)
++ return NULL;
++
++ sb->s_root = root;
++ if(!dev->is_checkpointed)
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
++ 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, 39))
++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs_mount,
++#else
++ .get_sb = yaffs_read_super,
++#endif
++ .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
++
++
++#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, 39))
++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs2_mount,
++#else
++ .get_sb = yaffs2_read_super,
++#endif
++ .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
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++static struct proc_dir_entry *my_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
++{
++ struct yaffs_param *param = &dev->param;
++ int bs[10];
++
++ yaffs_count_blocks_by_state(dev,bs);
++
++ buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
++ buf += sprintf(buf, "end_block............ %d\n", param->end_block);
++ buf += sprintf(buf, "total_bytes_per_chunk %d\n",
++ param->total_bytes_per_chunk);
++ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
++ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
++ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
++ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
++ buf += sprintf(buf, "empty_lost_n_found... %d\n",
++ param->empty_lost_n_found);
++ buf += sprintf(buf, "disable_lazy_load.... %d\n",
++ param->disable_lazy_load);
++ buf += sprintf(buf, "disable_bad_block_mrk %d\n",
++ param->disable_bad_block_marking);
++ buf += sprintf(buf, "refresh_period....... %d\n",
++ param->refresh_period);
++ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
++ buf += sprintf(buf, "n_reserved_blocks.... %d\n",
++ param->n_reserved_blocks);
++ buf += sprintf(buf, "always_check_erased.. %d\n",
++ param->always_check_erased);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "block count by state\n");
++ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
++ bs[0], bs[1], bs[2], bs[3], bs[4]);
++ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
++ bs[5], bs[6], bs[7], bs[8], bs[9]);
++
++ return buf;
++}
++
++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
++{
++ buf += sprintf(buf, "max file size....... %lld\n",
++ (long long) yaffs_max_file_size(dev));
++ buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
++ dev->data_bytes_per_chunk);
++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
++ buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
++ dev->blocks_in_checkpt);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
++ buf += sprintf(buf, "passive_gc_count..... %u\n",
++ dev->passive_gc_count);
++ buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
++ dev->oldest_dirty_gc_count);
++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
++ buf += sprintf(buf, "n_retried_writes..... %u\n",
++ dev->n_retried_writes);
++ buf += sprintf(buf, "n_retired_blocks..... %u\n",
++ dev->n_retired_blocks);
++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
++ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
++ dev->n_tags_ecc_fixed);
++ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
++ dev->n_tags_ecc_unfixed);
++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
++ buf += sprintf(buf, "n_unlinked_files..... %u\n",
++ dev->n_unlinked_files);
++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
++ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
++ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
++
++ 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 dev_list.
++ * 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,
++ "Multi-version YAFFS built:" __DATE__ " " __TIME__
++ "\n");
++ else if (step == 1)
++ buf += sprintf(buf, "\n");
++ else {
++ step -= 2;
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (n < (step & ~1)) {
++ n += 2;
++ continue;
++ }
++ if ((step & 1) == 0) {
++ buf +=
++ sprintf(buf, "\nDevice %d \"%s\"\n", n,
++ dev->param.name);
++ buf = yaffs_dump_dev_part0(buf, dev);
++ } else {
++ buf = yaffs_dump_dev_part1(buf, dev);
++ }
++
++ break;
++ }
++ mutex_unlock(&yaffs_context_lock);
++ }
++
++ 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},
++ {"background", YAFFS_TRACE_BACKGROUND},
++ {"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},
++ {"lock", YAFFS_TRACE_LOCK},
++ {"mtd", YAFFS_TRACE_MTD},
++ {"nandaccess", YAFFS_TRACE_NANDACCESS},
++ {"os", YAFFS_TRACE_OS},
++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++ {"scan", YAFFS_TRACE_SCAN},
++ {"mount", YAFFS_TRACE_MOUNT},
++ {"tracing", YAFFS_TRACE_TRACING},
++ {"sync", YAFFS_TRACE_SYNC},
++ {"write", YAFFS_TRACE_WRITE},
++ {"verify", YAFFS_TRACE_VERIFY},
++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
++ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
++ {"all", 0xffffffff},
++ {"none", 0},
++ {NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(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_trace_mask;
++
++ 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_trace_mask = rg | YAFFS_TRACE_ALWAYS;
++
++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
++
++ 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(KERN_DEBUG "%c%s\n", flag,
++ mask_flags[i].mask_name);
++ }
++ }
++
++ return count;
++}
++
++/* Debug strings are of the form:
++ * .bnnn print info on block n
++ * .cobjn,chunkn print nand chunk id for objn:chunkn
++ */
++
++static int yaffs_proc_debug_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++
++ char str[100];
++ char *p0;
++ char *p1;
++ long p1_val;
++ long p0_val;
++ char cmd;
++ struct list_head *item;
++
++ memset(str, 0, sizeof(str));
++ memcpy(str, buf, min(count, sizeof(str) -1));
++
++ cmd = str[1];
++
++ p0 = str + 2;
++
++ p1 = p0;
++
++ while (*p1 && *p1 != ',') {
++ p1++;
++ }
++ *p1 = '\0';
++ p1++;
++
++ p0_val = simple_strtol(p0, NULL, 0);
++ p1_val = simple_strtol(p1, NULL, 0);
++
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (cmd == 'b') {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev,p0_val);
++
++ if(bi) {
++ printk("Block %d: state %d, retire %d, use %d, seq %d\n",
++ (int)p0_val, bi->block_state,
++ bi->needs_retiring, bi->pages_in_use,
++ bi->seq_number);
++ }
++ } else if (cmd == 'c') {
++ struct yaffs_obj *obj;
++ int nand_chunk;
++
++ obj = yaffs_find_by_number(dev, p0_val);
++ if (!obj)
++ printk("No obj %d\n", (int)p0_val);
++ else {
++ if(p1_val == 0)
++ nand_chunk = obj->hdr_chunk;
++ else
++ nand_chunk =
++ yaffs_find_chunk_in_file(obj,
++ p1_val, NULL);
++ printk("Nand chunk for %d:%d is %d\n",
++ (int)p0_val, (int)p1_val, nand_chunk);
++ }
++ }
++ }
++
++ mutex_unlock(&yaffs_context_lock);
++
++ return count;
++}
++
++static int yaffs_proc_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ if (buf[0] == '.')
++ return yaffs_proc_debug_write(file, buf, count, data);
++ return yaffs_proc_write_trace_options(file, buf, count, data);
++}
++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
++
++/* 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[] = {
++ {&yaffs_fs_type, 0},
++ {&yaffs2_fs_type, 0},
++ {NULL, 0}
++};
++
++static int __init init_yaffs_fs(void)
++{
++ int error = 0;
++ struct file_system_to_install *fsinst;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " Installing.");
++
++ mutex_init(&yaffs_context_lock);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ /* Install the proc_fs entries */
++ my_proc_entry = create_proc_entry("yaffs",
++ S_IRUGO | S_IFREG, YPROC_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;
++ }
++#endif
++
++ /* 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;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " removing.");
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ remove_proc_entry("yaffs", YPROC_ROOT);
++#endif
++
++ 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-2011");
++MODULE_LICENSE("GPL");
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.10.40/fs/yaffs2/yaffs_yaffs1.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_yaffs1.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,422 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_yaffs1.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++#include "yaffs_attribs.h"
++
++int yaffs1_scan(struct yaffs_dev *dev)
++{
++ struct yaffs_ext_tags tags;
++ int blk;
++ int result;
++ int chunk;
++ int c;
++ int deleted;
++ enum yaffs_block_state state;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int alloc_failed = 0;
++ struct yaffs_shadow_fixer *shadow_fixers = NULL;
++ u8 *chunk_data;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs1_scan starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, state, seq_number);
++
++ if (state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ }
++ bi++;
++ }
++
++ /* For each block.... */
++ for (blk = dev->internal_start_block;
++ !alloc_failed && blk <= dev->internal_end_block; blk++) {
++
++ cond_resched();
++
++ bi = yaffs_get_block_info(dev, blk);
++ state = bi->block_state;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ for (c = 0;
++ !alloc_failed && c < dev->param.chunks_per_block &&
++ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
++ /* Read the tags and decide what to do */
++ chunk = blk * dev->param.chunks_per_block + c;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
++ tags.is_deleted) {
++ /* YAFFS1 only...
++ * A deleted chunk
++ */
++ deleted++;
++ dev->n_free_chunks++;
++ } else if (!tags.chunk_used) {
++ /* An unassigned chunk in the block
++ * This means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (c == 0) {
++ /* We're looking at the first chunk in
++ *the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ /* this is the block being allocated */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, c);
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = c;
++ dev->alloc_block_finder = blk;
++
++ }
++
++ dev->n_free_chunks +=
++ (dev->param.chunks_per_block - c);
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ unsigned int endpos;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ /* PutChunkIntoFile checks for a clash
++ * (two data chunks with the same chunk_id).
++ */
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in) {
++ if (!yaffs_put_chunk_in_file
++ (in, tags.chunk_id, chunk, 1))
++ alloc_failed = 1;
++ }
++
++ endpos =
++ (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk +
++ tags.n_bytes;
++ if (in &&
++ in->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE &&
++ in->variant.file_variant.scanned_size <
++ endpos) {
++ in->variant.file_variant.scanned_size =
++ endpos;
++ if (!dev->param.use_header_file_size) {
++ in->variant.
++ file_variant.file_size =
++ in->variant.
++ file_variant.scanned_size;
++ }
++
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Make the object
++ */
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ in = yaffs_find_by_number(dev, tags.obj_id);
++ if (in && in->variant_type != oh->type) {
++ /* This should not happen, but somehow
++ * Wev'e ended up with an obj_id that
++ * has been reused but not yet deleted,
++ * and worse still it has changed type.
++ * Delete the old object.
++ */
++
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ oh->type);
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in && oh->shadows_obj > 0) {
++
++ struct yaffs_shadow_fixer *fixer;
++ fixer =
++ kmalloc(sizeof
++ (struct yaffs_shadow_fixer),
++ GFP_NOFS);
++ if (fixer) {
++ fixer->next = shadow_fixers;
++ shadow_fixers = fixer;
++ fixer->obj_id = tags.obj_id;
++ fixer->shadowed_id =
++ oh->shadows_obj;
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Shadow fixer: %d shadows %d",
++ fixer->obj_id,
++ fixer->shadowed_id);
++
++ }
++
++ }
++
++ if (in && in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate and need to
++ * resolve it. */
++
++ unsigned existing_serial = in->serial;
++ unsigned new_serial =
++ tags.serial_number;
++
++ if (((existing_serial + 1) & 3) ==
++ new_serial) {
++ /* Use new one - destroy the
++ * exisiting one */
++ yaffs_chunk_del(dev,
++ in->hdr_chunk,
++ 1, __LINE__);
++ in->valid = 0;
++ } else {
++ /* Use existing - destroy
++ * this one. */
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++ }
++ }
++
++ if (in && !in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ } else if (in && !in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ in->dirty = 0;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (!parent)
++ alloc_failed = 1;
++ if (parent && parent->variant_type ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.
++ children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, a problem....
++ * We're trying to use a
++ * non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (dev->param.
++ use_header_file_size)
++ in->variant.
++ file_variant.file_size
++ = yaffs_oh_to_size(oh);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.
++ hardlink_variant.equiv_id =
++ oh->equiv_id;
++ list_add(&in->hard_links,
++ &hard_list);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.
++ alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.
++ symlink_variant.alias)
++ alloc_failed = 1;
++ break;
++ }
++ }
++ }
++ }
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning,
++ * then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ /* If the block was partially allocated then
++ * treat it as fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ bi->block_state = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ yaffs_block_became_dirty(dev, blk);
++ }
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add
++ * these hardlinks.
++ */
++
++ yaffs_link_fixup(dev, &hard_list);
++
++ /*
++ * Fix up any shadowed objects.
++ * There should not be more than one of these.
++ */
++ {
++ struct yaffs_shadow_fixer *fixer;
++ struct yaffs_obj *obj;
++
++ while (shadow_fixers) {
++ fixer = shadow_fixers;
++ shadow_fixers = fixer->next;
++ /* Complete the rename transaction by deleting the
++ * shadowed object then setting the object header
++ to unshadowed.
++ */
++ obj = yaffs_find_by_number(dev, fixer->shadowed_id);
++ if (obj)
++ yaffs_del_obj(obj);
++
++ obj = yaffs_find_by_number(dev, fixer->obj_id);
++
++ if (obj)
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ kfree(fixer);
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.10.40/fs/yaffs2/yaffs_yaffs1.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_yaffs1.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS1_H__
++#define __YAFFS_YAFFS1_H__
++
++#include "yaffs_guts.h"
++int yaffs1_scan(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.10.40/fs/yaffs2/yaffs_yaffs2.c
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_yaffs2.c 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,1534 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_checkptrw.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_verify.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/*
++ * Checkpoints are really no benefit on very small partitions.
++ *
++ * To save space on small partitions don't bother with checkpoints unless
++ * the partition is at least this big.
++ */
++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
++#define YAFFS_SMALL_HOLE_THRESHOLD 4
++
++/*
++ * Oldest Dirty Sequence Number handling.
++ */
++
++/* yaffs_calc_oldest_dirty_seq()
++ * yaffs2_find_oldest_dirty_seq()
++ * Calculate the oldest dirty sequence number if we don't know it.
++ */
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ int i;
++ unsigned seq;
++ unsigned block_no = 0;
++ struct yaffs_block_info *b;
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ /* Find the oldest dirty sequence number. */
++ seq = dev->seq_number + 1;
++ b = dev->block_info;
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
++ (b->pages_in_use - b->soft_del_pages) <
++ dev->param.chunks_per_block &&
++ b->seq_number < seq) {
++ seq = b->seq_number;
++ block_no = i;
++ }
++ b++;
++ }
++
++ if (block_no) {
++ dev->oldest_dirty_seq = seq;
++ dev->oldest_dirty_block = block_no;
++ }
++}
++
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->oldest_dirty_seq)
++ yaffs_calc_oldest_dirty_seq(dev);
++}
++
++/*
++ * yaffs_clear_oldest_dirty_seq()
++ * Called when a block is erased or marked bad. (ie. when its seq_number
++ * becomes invalid). If the value matches the oldest then we clear
++ * dev->oldest_dirty_seq to force its recomputation.
++ */
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++ }
++}
++
++/*
++ * yaffs2_update_oldest_dirty_seq()
++ * Update the oldest dirty sequence number whenever we dirty a block.
++ * Only do this if the oldest_dirty_seq is actually being tracked.
++ */
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (dev->oldest_dirty_seq) {
++ if (dev->oldest_dirty_seq > bi->seq_number) {
++ dev->oldest_dirty_seq = bi->seq_number;
++ dev->oldest_dirty_block = block_no;
++ }
++ }
++}
++
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return 1; /* disqualification only applies to yaffs2. */
++
++ if (!bi->has_shrink_hdr)
++ return 1; /* can gc */
++
++ yaffs2_find_oldest_dirty_seq(dev);
++
++ /* Can't do gc of this block if there are any blocks older than this
++ * one that have discarded pages.
++ */
++ return (bi->seq_number <= dev->oldest_dirty_seq);
++}
++
++/*
++ * yaffs2_find_refresh_block()
++ * periodically finds the oldest full block by sequence number for refreshing.
++ * Only for yaffs2.
++ */
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
++{
++ u32 b;
++ u32 oldest = 0;
++ u32 oldest_seq = 0;
++ struct yaffs_block_info *bi;
++
++ if (!dev->param.is_yaffs2)
++ return oldest;
++
++ /*
++ * If refresh period < 10 then refreshing is disabled.
++ */
++ if (dev->param.refresh_period < 10)
++ return oldest;
++
++ /*
++ * Fix broken values.
++ */
++ if (dev->refresh_skip > dev->param.refresh_period)
++ dev->refresh_skip = dev->param.refresh_period;
++
++ if (dev->refresh_skip > 0)
++ return oldest;
++
++ /*
++ * Refresh skip is now zero.
++ * We'll do a refresh this time around....
++ * Update the refresh skip and find the oldest block.
++ */
++ dev->refresh_skip = dev->param.refresh_period;
++ dev->refresh_count++;
++ bi = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++
++ if (oldest < 1 || bi->seq_number < oldest_seq) {
++ oldest = b;
++ oldest_seq = bi->seq_number;
++ }
++ }
++ bi++;
++ }
++
++ if (oldest > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC refresh count %d selected block %d with seq_number %d",
++ dev->refresh_count, oldest, oldest_seq);
++ }
++
++ return oldest;
++}
++
++int yaffs2_checkpt_required(struct yaffs_dev *dev)
++{
++ int nblocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ return !dev->param.skip_checkpt_wr &&
++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
++}
++
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
++{
++ int retval;
++ int n_bytes = 0;
++ int n_blocks;
++ int dev_blocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
++ /* Not a valid value so recalculate */
++ dev_blocks = dev->param.end_block - dev->param.start_block + 1;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(struct yaffs_checkpt_dev);
++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
++ n_bytes += dev_blocks * dev->chunk_bit_stride;
++ n_bytes +=
++ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
++ dev->n_obj;
++ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(u32); /* checksum */
++
++ /* Round up and add 2 blocks to allow for some bad blocks,
++ * so add 3 */
++
++ n_blocks =
++ (n_bytes /
++ (dev->data_bytes_per_chunk *
++ dev->param.chunks_per_block)) + 3;
++
++ dev->checkpoint_blocks_required = n_blocks;
++ }
++
++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
++ if (retval < 0)
++ retval = 0;
++ return retval;
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++
++ memset(&cp, 0, sizeof(cp));
++
++ cp.struct_type = sizeof(cp);
++ cp.magic = YAFFS_MAGIC;
++ cp.version = YAFFS_CHECKPOINT_VERSION;
++ cp.head = (head) ? 1 : 0;
++
++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok)
++ ok = (cp.struct_type == sizeof(cp)) &&
++ (cp.magic == YAFFS_MAGIC) &&
++ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++ (cp.head == ((head) ? 1 : 0));
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
++ struct yaffs_dev *dev)
++{
++ cp->n_erased_blocks = dev->n_erased_blocks;
++ cp->alloc_block = dev->alloc_block;
++ cp->alloc_page = dev->alloc_page;
++ cp->n_free_chunks = dev->n_free_chunks;
++
++ cp->n_deleted_files = dev->n_deleted_files;
++ cp->n_unlinked_files = dev->n_unlinked_files;
++ cp->n_bg_deletions = dev->n_bg_deletions;
++ cp->seq_number = dev->seq_number;
++
++}
++
++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
++ struct yaffs_checkpt_dev *cp)
++{
++ dev->n_erased_blocks = cp->n_erased_blocks;
++ dev->alloc_block = cp->alloc_block;
++ dev->alloc_page = cp->alloc_page;
++ dev->n_free_chunks = cp->n_free_chunks;
++
++ dev->n_deleted_files = cp->n_deleted_files;
++ dev->n_unlinked_files = cp->n_unlinked_files;
++ dev->n_bg_deletions = cp->n_bg_deletions;
++ dev->seq_number = cp->seq_number;
++}
++
++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ int ok;
++
++ /* Write device runtime values */
++ yaffs2_dev_to_checkpt_dev(&cp, dev);
++ cp.struct_type = sizeof(cp);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ /* Write block info */
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
++ if (!ok)
++ return 0;
++
++ /* Write chunk bits */
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks =
++ (dev->internal_end_block - dev->internal_start_block + 1);
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ if (cp.struct_type != sizeof(cp))
++ return 0;
++
++ yaffs_checkpt_dev_to_dev(dev, &cp);
++
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++
++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
++
++ if (!ok)
++ return 0;
++
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++
++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
++ struct yaffs_obj *obj)
++{
++ cp->obj_id = obj->obj_id;
++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
++ cp->hdr_chunk = obj->hdr_chunk;
++ cp->variant_type = obj->variant_type;
++ cp->deleted = obj->deleted;
++ cp->soft_del = obj->soft_del;
++ cp->unlinked = obj->unlinked;
++ cp->fake = obj->fake;
++ cp->rename_allowed = obj->rename_allowed;
++ cp->unlink_allowed = obj->unlink_allowed;
++ cp->serial = obj->serial;
++ cp->n_data_chunks = obj->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
++}
++
++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
++ struct yaffs_checkpt_obj *cp)
++{
++ struct yaffs_obj *parent;
++
++ if (obj->variant_type != cp->variant_type) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
++ cp->obj_id, cp->variant_type, cp->hdr_chunk,
++ obj->variant_type);
++ return 0;
++ }
++
++ obj->obj_id = cp->obj_id;
++
++ if (cp->parent_id)
++ parent = yaffs_find_or_create_by_number(obj->my_dev,
++ cp->parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ else
++ parent = NULL;
++
++ if (parent) {
++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
++ cp->obj_id, cp->parent_id,
++ cp->variant_type, cp->hdr_chunk,
++ parent->variant_type);
++ return 0;
++ }
++ yaffs_add_obj_to_dir(parent, obj);
++ }
++
++ obj->hdr_chunk = cp->hdr_chunk;
++ obj->variant_type = cp->variant_type;
++ obj->deleted = cp->deleted;
++ obj->soft_del = cp->soft_del;
++ obj->unlinked = cp->unlinked;
++ obj->fake = cp->fake;
++ obj->rename_allowed = cp->rename_allowed;
++ obj->unlink_allowed = cp->unlink_allowed;
++ obj->serial = cp->serial;
++ obj->n_data_chunks = cp->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
++
++ if (obj->hdr_chunk > 0)
++ obj->lazy_loaded = 1;
++ return 1;
++}
++
++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
++ struct yaffs_tnode *tn, u32 level,
++ int chunk_offset)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++ int ok = 1;
++ u32 base_offset;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (!tn->internal[i])
++ continue;
++ ok = yaffs2_checkpt_tnode_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS) + i);
++ }
++ return ok;
++ }
++
++ /* Level 0 tnode */
++ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
++ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
++ sizeof(base_offset));
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++
++ return ok;
++}
++
++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 end_marker = ~0;
++ int ok = 1;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return ok;
++
++ ok = yaffs2_checkpt_tnode_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.file_variant.
++ top_level, 0);
++ if (ok)
++ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
++ sizeof(end_marker)) == sizeof(end_marker));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 base_chunk;
++ int ok = 1;
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
++ struct yaffs_tnode *tn;
++ int nread = 0;
++
++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
++ sizeof(base_chunk));
++
++ while (ok && (~base_chunk)) {
++ nread++;
++ /* Read level 0 tnode */
++
++ tn = yaffs_get_tnode(dev);
++ if (tn)
++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++ else
++ ok = 0;
++
++ if (tn && ok)
++ ok = yaffs_add_find_tnode_0(dev,
++ file_stuct_ptr,
++ base_chunk, tn) ? 1 : 0;
++
++ if (ok)
++ ok = (yaffs2_checkpt_rd
++ (dev, &base_chunk,
++ sizeof(base_chunk)) == sizeof(base_chunk));
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read tnodes %d records, last %d. ok %d",
++ nread, base_chunk, ok);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int i;
++ int ok = 1;
++ struct list_head *lh;
++
++ /* Iterate through the objects in each hash entry,
++ * dumping them to the checkpointing stream.
++ */
++
++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ if (!obj->defered_free) {
++ yaffs2_obj_checkpt_obj(&cp, obj);
++ cp.struct_type = sizeof(cp);
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
++ cp.obj_id, cp.parent_id,
++ cp.variant_type, cp.hdr_chunk, obj);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp,
++ sizeof(cp)) == sizeof(cp));
++
++ if (ok &&
++ obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE)
++ ok = yaffs2_wr_checkpt_tnodes(obj);
++ }
++ }
++ }
++
++ /* Dump end of list */
++ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
++ cp.struct_type = sizeof(cp);
++
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int ok = 1;
++ int done = 0;
++ LIST_HEAD(hard_list);
++
++
++ while (ok && !done) {
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (cp.struct_type != sizeof(cp)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "struct size %d instead of %d ok %d",
++ cp.struct_type, (int)sizeof(cp), ok);
++ ok = 0;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read object %d parent %d type %d chunk %d ",
++ cp.obj_id, cp.parent_id, cp.variant_type,
++ cp.hdr_chunk);
++
++ if (ok && cp.obj_id == ~0) {
++ done = 1;
++ } else if (ok) {
++ obj =
++ yaffs_find_or_create_by_number(dev, cp.obj_id,
++ cp.variant_type);
++ if (obj) {
++ ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
++ if (!ok)
++ break;
++ if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs2_rd_checkpt_tnodes(obj);
++ } else if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_HARDLINK) {
++ list_add(&obj->hard_links, &hard_list);
++ }
++ } else {
++ ok = 0;
++ }
++ }
++ }
++
++ if (ok)
++ yaffs_link_fixup(dev, &hard_list);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum);
++
++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
++ sizeof(checkpt_sum));
++
++ if (!ok)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum0;
++ u32 checkpt_sum1;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
++
++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
++ sizeof(checkpt_sum1));
++
++ if (!ok)
++ return 0;
++
++ if (checkpt_sum0 != checkpt_sum1)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!yaffs2_checkpt_required(dev)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint write");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 1);
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint device");
++ ok = yaffs2_wr_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint objects");
++ ok = yaffs2_wr_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok)
++ ok = yaffs2_wr_checkpt_sum(dev);
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return dev->is_checkpointed;
++}
++
++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!dev->param.is_yaffs2)
++ ok = 0;
++
++ if (ok && dev->param.skip_checkpt_rd) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint read");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint device");
++ ok = yaffs2_rd_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint objects");
++ ok = yaffs2_rd_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok) {
++ ok = yaffs2_rd_checkpt_sum(dev);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint checksum %d", ok);
++ }
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return ok ? 1 : 0;
++}
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
++{
++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
++ dev->is_checkpointed = 0;
++ yaffs2_checkpt_invalidate_stream(dev);
++ }
++ if (dev->param.sb_dirty_fn)
++ dev->param.sb_dirty_fn(dev);
++}
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "save entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++
++ if (!dev->is_checkpointed) {
++ yaffs2_checkpt_invalidate(dev);
++ yaffs2_wr_checkpt_data(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++ "save exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return dev->is_checkpointed;
++}
++
++int yaffs2_checkpt_restore(struct yaffs_dev *dev)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ retval = yaffs2_rd_checkpt_data(dev);
++
++ if (dev->is_checkpointed) {
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return retval;
++}
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
++{
++ /* if new_size > old_file_size.
++ * We're going to be writing a hole.
++ * If the hole is small then write zeros otherwise write a start
++ * of hole marker.
++ */
++ loff_t old_file_size;
++ loff_t increase;
++ int small_hole;
++ int result = YAFFS_OK;
++ struct yaffs_dev *dev = NULL;
++ u8 *local_buffer = NULL;
++ int small_increase_ok = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ dev = obj->my_dev;
++
++ /* Bail out if not yaffs2 mode */
++ if (!dev->param.is_yaffs2)
++ return YAFFS_OK;
++
++ old_file_size = obj->variant.file_variant.file_size;
++
++ if (new_size <= old_file_size)
++ return YAFFS_OK;
++
++ increase = new_size - old_file_size;
++
++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
++ small_hole = 1;
++ else
++ small_hole = 0;
++
++ if (small_hole)
++ local_buffer = yaffs_get_temp_buffer(dev);
++
++ if (local_buffer) {
++ /* fill hole with zero bytes */
++ loff_t pos = old_file_size;
++ int this_write;
++ int written;
++ memset(local_buffer, 0, dev->data_bytes_per_chunk);
++ small_increase_ok = 1;
++
++ while (increase > 0 && small_increase_ok) {
++ this_write = increase;
++ if (this_write > dev->data_bytes_per_chunk)
++ this_write = dev->data_bytes_per_chunk;
++ written =
++ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
++ 0);
++ if (written == this_write) {
++ pos += this_write;
++ increase -= this_write;
++ } else {
++ small_increase_ok = 0;
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++
++ /* If out of space then reverse any chunks we've added */
++ if (!small_increase_ok)
++ yaffs_resize_file_down(obj, old_file_size);
++ }
++
++ if (!small_increase_ok &&
++ obj->parent &&
++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
++ /* Write a hole start header with the old file size */
++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
++ }
++
++ return result;
++}
++
++struct yaffs_block_index {
++ int seq;
++ int block;
++};
++
++static int yaffs2_ybicmp(const void *a, const void *b)
++{
++ int aseq = ((struct yaffs_block_index *)a)->seq;
++ int bseq = ((struct yaffs_block_index *)b)->seq;
++ int ablock = ((struct yaffs_block_index *)a)->block;
++ int bblock = ((struct yaffs_block_index *)b)->block;
++
++ if (aseq == bseq)
++ return ablock - bblock;
++
++ return aseq - bseq;
++}
++
++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int blk, int chunk_in_block,
++ int *found_chunks,
++ u8 *chunk_data,
++ struct list_head *hard_list,
++ int summary_available)
++{
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int equiv_id;
++ loff_t file_size;
++ int is_shrink;
++ int is_unlinked;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++ int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
++ struct yaffs_file_var *file_var;
++ struct yaffs_hardlink_var *hl_var;
++ struct yaffs_symlink_var *sl_var;
++
++ if (summary_available) {
++ result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
++ tags.seq_number = bi->seq_number;
++ }
++
++ if (!summary_available || tags.obj_id == 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
++ dev->tags_used++;
++ } else {
++ dev->summary_used++;
++ }
++
++ /* Let's have a good look at this chunk... */
++
++ if (!tags.chunk_used) {
++ /* An unassigned chunk in the block.
++ * If there are used chunks after this one, then
++ * it is a chunk that was skipped due to failing
++ * the erased check. Just skip it so that it can
++ * be deleted.
++ * But, more typically, We get here when this is
++ * an unallocated chunk and his means that
++ * either the block is empty or this is the one
++ * being allocated from
++ */
++
++ if (*found_chunks) {
++ /* This is a chunk that was skipped due
++ * to failing the erased check */
++ } else if (chunk_in_block == 0) {
++ /* We're looking at the first chunk in
++ * the block so the block is unused */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ if (dev->seq_number == bi->seq_number) {
++ /* Allocating from this block*/
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, chunk_in_block);
++
++ bi->block_state =
++ YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = chunk_in_block;
++ dev->alloc_block_finder = blk;
++ } else {
++ /* This is a partially written block
++ * that is not the current
++ * allocation block.
++ */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Partially written block %d detected. gc will fix this.",
++ blk);
++ }
++ }
++ }
++
++ dev->n_free_chunks++;
++
++ } else if (tags.ecc_result ==
++ YAFFS_ECC_RESULT_UNFIXED) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Unfixed ECC in chunk(%d:%d), chunk ignored",
++ blk, chunk_in_block);
++ dev->n_free_chunks++;
++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
++ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
++ tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
++ (tags.chunk_id > 0 &&
++ tags.n_bytes > dev->data_bytes_per_chunk) ||
++ tags.seq_number != bi->seq_number) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
++ blk, chunk_in_block, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++ dev->n_free_chunks++;
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ loff_t endpos;
++ loff_t chunk_base = (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk;
++
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!in)
++ /* Out of memory */
++ alloc_failed = 1;
++
++ if (in &&
++ in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
++ chunk_base < in->variant.file_variant.shrink_size) {
++ /* This has not been invalidated by
++ * a resize */
++ if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
++ chunk, -1))
++ alloc_failed = 1;
++
++ /* File size is calculated by looking at
++ * the data chunks if we have not
++ * seen an object header yet.
++ * Stop this practice once we find an
++ * object header.
++ */
++ endpos = chunk_base + tags.n_bytes;
++
++ if (!in->valid &&
++ in->variant.file_variant.scanned_size < endpos) {
++ in->variant.file_variant.
++ scanned_size = endpos;
++ in->variant.file_variant.
++ file_size = endpos;
++ }
++ } else if (in) {
++ /* This chunk has been invalidated by a
++ * resize, or a past file deletion
++ * so delete the chunk*/
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make
++ * the object
++ */
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ oh = NULL;
++ in = NULL;
++
++ if (tags.extra_available) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ tags.extra_obj_type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ if (!in ||
++ (!in->valid && dev->param.disable_lazy_load) ||
++ tags.extra_shadows ||
++ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
++
++ /* If we don't have valid info then we
++ * need to read the chunk
++ * TODO In future we can probably defer
++ * reading the chunk and living with
++ * invalid data until needed.
++ */
++
++ result = yaffs_rd_chunk_tags_nand(dev,
++ chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ if (dev->param.inband_tags) {
++ /* Fix up the header if they got
++ * corrupted by inband tags */
++ oh->shadows_obj =
++ oh->inband_shadowed_obj_id;
++ oh->is_shrink =
++ oh->inband_is_shrink;
++ }
++
++ if (!in) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id, oh->type);
++ if (!in)
++ alloc_failed = 1;
++ }
++ }
++
++ if (!in) {
++ /* TODO Hoosterman we have a problem! */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
++ tags.obj_id, chunk);
++ return YAFFS_FAIL;
++ }
++
++ if (in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate that will be
++ * discarded, but we first have to suck
++ * out resize info if it is a file.
++ */
++ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
++ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
++ (tags.extra_available &&
++ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ )) {
++ loff_t this_size = (oh) ?
++ yaffs_oh_to_size(oh) :
++ tags.extra_file_size;
++ u32 parent_obj_id = (oh) ?
++ oh->parent_obj_id :
++ tags.extra_parent_id;
++
++ is_shrink = (oh) ?
++ oh->is_shrink :
++ tags.extra_is_shrink;
++
++ /* If it is deleted (unlinked
++ * at start also means deleted)
++ * we treat the file size as
++ * being zeroed at this point.
++ */
++ if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
++ parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
++ this_size = 0;
++ is_shrink = 1;
++ }
++
++ if (is_shrink &&
++ in->variant.file_variant.shrink_size >
++ this_size)
++ in->variant.file_variant.shrink_size =
++ this_size;
++
++ if (is_shrink)
++ bi->has_shrink_hdr = 1;
++ }
++ /* Use existing - destroy this one. */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++
++ if (!in->valid && in->variant_type !=
++ (oh ? oh->type : tags.extra_obj_type)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
++ oh ? oh->type : tags.extra_obj_type,
++ in->variant_type, tags.obj_id,
++ chunk);
++ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
++ }
++
++ if (!in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++
++ if (oh) {
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->lazy_loaded = 0;
++ } else {
++ in->lazy_loaded = 1;
++ }
++ in->hdr_chunk = chunk;
++
++ } else if (!in->valid) {
++ /* we need to load this info */
++ in->valid = 1;
++ in->hdr_chunk = chunk;
++ if (oh) {
++ in->variant_type = oh->type;
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++
++ if (oh->shadows_obj > 0)
++ yaffs_handle_shadowed_obj(dev,
++ oh->shadows_obj, 1);
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ parent = yaffs_find_or_create_by_number(dev,
++ oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = yaffs_oh_to_size(oh);
++ is_shrink = oh->is_shrink;
++ equiv_id = oh->equiv_id;
++ } else {
++ in->variant_type = tags.extra_obj_type;
++ parent = yaffs_find_or_create_by_number(dev,
++ tags.extra_parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = tags.extra_file_size;
++ is_shrink = tags.extra_is_shrink;
++ equiv_id = tags.extra_equiv_id;
++ in->lazy_loaded = 1;
++ }
++ in->dirty = 0;
++
++ if (!parent)
++ alloc_failed = 1;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ if (parent &&
++ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * Trying to use a non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++ yaffs_add_obj_to_dir(parent, in);
++
++ is_unlinked = (parent == dev->del_dir) ||
++ (parent == dev->unlinked_dir);
++
++ if (is_shrink)
++ /* Mark the block */
++ bi->has_shrink_hdr = 1;
++
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent
++ * object is scanned we put them all in a list.
++ * After scanning is complete, we should have all the
++ * objects, so we run through this list and fix up all
++ * the chains.
++ */
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ file_var = &in->variant.file_variant;
++ if (file_var->scanned_size < file_size) {
++ /* This covers the case where the file
++ * size is greater than the data held.
++ * This will happen if the file is
++ * resized to be larger than its
++ * current data extents.
++ */
++ file_var->file_size = file_size;
++ file_var->scanned_size = file_size;
++ }
++
++ if (file_var->shrink_size > file_size)
++ file_var->shrink_size = file_size;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ hl_var = &in->variant.hardlink_variant;
++ if (!is_unlinked) {
++ hl_var->equiv_id = equiv_id;
++ list_add(&in->hard_links, hard_list);
++ }
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ sl_var = &in->variant.symlink_variant;
++ if (oh) {
++ sl_var->alias =
++ yaffs_clone_str(oh->alias);
++ if (!sl_var->alias)
++ alloc_failed = 1;
++ }
++ break;
++ }
++ }
++ }
++ return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
++}
++
++int yaffs2_scan_backwards(struct yaffs_dev *dev)
++{
++ int blk;
++ int block_iter;
++ int start_iter;
++ int end_iter;
++ int n_to_scan = 0;
++ enum yaffs_block_state state;
++ int c;
++ int deleted;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ u8 *chunk_data;
++ int found_chunks;
++ int alloc_failed = 0;
++ struct yaffs_block_index *block_index = NULL;
++ int alt_block_index = 0;
++ int summary_available;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ block_index =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
++
++ if (!block_index) {
++ block_index =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_index));
++ alt_block_index = 1;
++ }
++
++ if (!block_index) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards() could not allocate block index!"
++ );
++ return YAFFS_FAIL;
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, bi->block_state, seq_number);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ dev->blocks_in_checkpt++;
++
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ } else if (bi->block_state ==
++ YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* Determine the highest sequence number */
++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++ block_index[n_to_scan].seq = seq_number;
++ block_index[n_to_scan].block = blk;
++ n_to_scan++;
++ if (seq_number >= dev->seq_number)
++ dev->seq_number = seq_number;
++ } else {
++ /* TODO: Nasty sequence number! */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Block scanning block %d has bad sequence number %d",
++ blk, seq_number);
++ }
++ }
++ bi++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
++
++ cond_resched();
++
++ /* Sort the blocks by sequence number */
++ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
++ yaffs2_ybicmp, NULL);
++
++ cond_resched();
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "...done");
++
++ /* Now scan the blocks looking at the data. */
++ start_iter = 0;
++ end_iter = n_to_scan - 1;
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
++
++ /* For each block.... backwards */
++ for (block_iter = end_iter;
++ !alloc_failed && block_iter >= start_iter;
++ block_iter--) {
++ /* Cooperative multitasking! This loop can run for so
++ long that watchdog timers expire. */
++ cond_resched();
++
++ /* get the block to scan in the correct order */
++ blk = block_index[block_iter].block;
++ bi = yaffs_get_block_info(dev, blk);
++ deleted = 0;
++
++ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
++
++ /* For each chunk in each block that needs scanning.... */
++ found_chunks = 0;
++ if (summary_available)
++ c = dev->chunks_per_summary - 1;
++ else
++ c = dev->param.chunks_per_block - 1;
++
++ for (/* c is already initialised */;
++ !alloc_failed && c >= 0 &&
++ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
++ c--) {
++ /* Scan backwards...
++ * Read the tags and decide what to do
++ */
++ if (yaffs2_scan_chunk(dev, bi, blk, c,
++ &found_chunks, chunk_data,
++ &hard_list, summary_available) ==
++ YAFFS_FAIL)
++ alloc_failed = 1;
++ }
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning, then the block
++ * is fully allocated. */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_block_became_dirty(dev, blk);
++ }
++ }
++
++ yaffs_skip_rest_of_block(dev);
++
++ if (alt_block_index)
++ vfree(block_index);
++ else
++ kfree(block_index);
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++ yaffs_link_fixup(dev, &hard_list);
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.10.40/fs/yaffs2/yaffs_yaffs2.h
+--- linux-3.10.40.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yaffs_yaffs2.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS2_H__
++#define __YAFFS_YAFFS2_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi);
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
++int yaffs2_checkpt_required(struct yaffs_dev *dev);
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
++int yaffs2_checkpt_save(struct yaffs_dev *dev);
++int yaffs2_checkpt_restore(struct yaffs_dev *dev);
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
++int yaffs2_scan_backwards(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.10.40.orig/fs/yaffs2/yportenv.h linux-3.10.40/fs/yaffs2/yportenv.h
+--- linux-3.10.40.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.10.40/fs/yaffs2/yportenv.h 2014-05-17 12:48:10.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#ifdef YAFFS_OUT_OF_TREE
++#include "moduleconfig.h"
++#endif
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/xattr.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/sort.h>
++#include <linux/bitops.h>
++
++/* These type wrappings are used to support Unicode names in WinCE. */
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#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 compile_time_assertion(assertion) \
++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++
++#define yaffs_printf(msk, fmt, ...) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
++
++#define yaffs_trace(msk, fmt, ...) do { \
++ if (yaffs_trace_mask & (msk)) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
++} while (0)
++
++
++#endif
diff --git a/target/linux/patches/3.11.10/arm-spitz.patch b/target/linux/patches/3.11.10/arm-spitz.patch
deleted file mode 100644
index aea848244..000000000
--- a/target/linux/patches/3.11.10/arm-spitz.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-http://lists.infradead.org/pipermail/linux-arm-kernel/2013-September/198444.html
-
-diff -Nur linux-3.9.11.orig/arch/arm/common/sharpsl_param.c linux-3.9.11/arch/arm/common/sharpsl_param.c
---- linux-3.9.11.orig/arch/arm/common/sharpsl_param.c 2013-07-21 02:16:17.000000000 +0200
-+++ linux-3.9.11/arch/arm/common/sharpsl_param.c 2013-09-18 16:27:10.000000000 +0200
-@@ -26,6 +26,7 @@
- #ifdef CONFIG_ARCH_SA1100
- #define PARAM_BASE 0xe8ffc000
- #else
-+#include <asm/memory.h>
- #define PARAM_BASE 0xa0000a00
- #endif
- #define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a )
-@@ -41,7 +42,12 @@
-
- void sharpsl_save_param(void)
- {
-- memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info));
-+#ifdef CONFIG_ARCH_SA1100
-+ void *param_start = (void *)PARAM_BASE;
-+#else
-+ void *param_start = phys_to_virt(PARAM_BASE);
-+#endif
-+ memcpy(&sharpsl_param, param_start, sizeof(struct sharpsl_param_info));
-
- if (sharpsl_param.comadj_keyword != COMADJ_MAGIC)
- sharpsl_param.comadj=-1;
diff --git a/target/linux/patches/3.11.10/raspberry.patch b/target/linux/patches/3.11.10/raspberry.patch
deleted file mode 100644
index 156e44201..000000000
--- a/target/linux/patches/3.11.10/raspberry.patch
+++ /dev/null
@@ -1,97980 +0,0 @@
-diff -Nur linux-3.11.10.orig/arch/arm/configs/bcmrpi_cutdown_defconfig linux-3.11.10/arch/arm/configs/bcmrpi_cutdown_defconfig
---- linux-3.11.10.orig/arch/arm/configs/bcmrpi_cutdown_defconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/configs/bcmrpi_cutdown_defconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,503 @@
-+CONFIG_EXPERIMENTAL=y
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+# CONFIG_UID16 is not set
-+# CONFIG_KALLSYMS is not set
-+CONFIG_EMBEDDED=y
-+# CONFIG_VM_EVENT_COUNTERS is not set
-+# CONFIG_COMPAT_BRK is not set
-+CONFIG_SLAB=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+# CONFIG_BLK_DEV_BSG is not set
-+CONFIG_ARCH_BCM2708=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_AEABI=y
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
-+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext3 rootwait"
-+CONFIG_CPU_IDLE=y
-+CONFIG_VFP=y
-+CONFIG_BINFMT_MISC=m
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_UNIX=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
-+CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_SYN_COOKIES=y
-+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_BEET is not set
-+# CONFIG_INET_LRO is not set
-+# CONFIG_INET_DIAG is not set
-+# CONFIG_IPV6 is not set
-+CONFIG_NET_PKTGEN=m
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRTTY_SIR=m
-+CONFIG_KINGSUN_DONGLE=m
-+CONFIG_KSDAZZLE_DONGLE=m
-+CONFIG_KS959_DONGLE=m
-+CONFIG_USB_IRDA=m
-+CONFIG_SIGMATEL_FIR=m
-+CONFIG_MCS_FIR=m
-+CONFIG_BT=m
-+CONFIG_BT_L2CAP=y
-+CONFIG_BT_SCO=y
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIBCM203X=m
-+CONFIG_BT_HCIBPA10X=m
-+CONFIG_BT_HCIBFUSB=m
-+CONFIG_BT_HCIVHCI=m
-+CONFIG_BT_MRVL=m
-+CONFIG_BT_MRVL_SDIO=m
-+CONFIG_BT_ATH3K=m
-+CONFIG_CFG80211=m
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_RC_PID=y
-+CONFIG_MAC80211_MESH=y
-+CONFIG_WIMAX=m
-+CONFIG_NET_9P=m
-+CONFIG_NFC=m
-+CONFIG_NFC_PN533=m
-+CONFIG_DEVTMPFS=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
-+CONFIG_BLK_DEV_NBD=m
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_CDROM_PKTCDVD=m
-+CONFIG_MISC_DEVICES=y
-+CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
-+CONFIG_BLK_DEV_SD=m
-+CONFIG_BLK_DEV_SR=m
-+CONFIG_SCSI_MULTI_LUN=y
-+# CONFIG_SCSI_LOWLEVEL is not set
-+CONFIG_NETDEVICES=y
-+CONFIG_TUN=m
-+CONFIG_PHYLIB=m
-+CONFIG_MDIO_BITBANG=m
-+CONFIG_NET_ETHERNET=y
-+# CONFIG_NETDEV_1000 is not set
-+# CONFIG_NETDEV_10000 is not set
-+CONFIG_LIBERTAS_THINFIRM=m
-+CONFIG_LIBERTAS_THINFIRM_USB=m
-+CONFIG_AT76C50X_USB=m
-+CONFIG_USB_ZD1201=m
-+CONFIG_USB_NET_RNDIS_WLAN=m
-+CONFIG_RTL8187=m
-+CONFIG_MAC80211_HWSIM=m
-+CONFIG_ATH_COMMON=m
-+CONFIG_ATH9K=m
-+CONFIG_ATH9K_HTC=m
-+CONFIG_CARL9170=m
-+CONFIG_B43=m
-+CONFIG_B43LEGACY=m
-+CONFIG_HOSTAP=m
-+CONFIG_IWM=m
-+CONFIG_LIBERTAS=m
-+CONFIG_LIBERTAS_USB=m
-+CONFIG_LIBERTAS_SDIO=m
-+CONFIG_P54_COMMON=m
-+CONFIG_P54_USB=m
-+CONFIG_RT2X00=m
-+CONFIG_RT2500USB=m
-+CONFIG_RT73USB=m
-+CONFIG_RT2800USB=m
-+CONFIG_RT2800USB_RT53XX=y
-+CONFIG_RTL8192CU=m
-+CONFIG_WL1251=m
-+CONFIG_WL12XX_MENU=m
-+CONFIG_ZD1211RW=m
-+CONFIG_MWIFIEX=m
-+CONFIG_MWIFIEX_SDIO=m
-+CONFIG_WIMAX_I2400M_USB=m
-+CONFIG_USB_CATC=m
-+CONFIG_USB_KAWETH=m
-+CONFIG_USB_PEGASUS=m
-+CONFIG_USB_RTL8150=m
-+CONFIG_USB_USBNET=y
-+CONFIG_USB_NET_AX8817X=m
-+CONFIG_USB_NET_CDCETHER=m
-+CONFIG_USB_NET_CDC_EEM=m
-+CONFIG_USB_NET_DM9601=m
-+CONFIG_USB_NET_SMSC75XX=m
-+CONFIG_USB_NET_SMSC95XX=y
-+CONFIG_USB_NET_GL620A=m
-+CONFIG_USB_NET_NET1080=m
-+CONFIG_USB_NET_PLUSB=m
-+CONFIG_USB_NET_MCS7830=m
-+CONFIG_USB_NET_CDC_SUBSET=m
-+CONFIG_USB_ALI_M5632=y
-+CONFIG_USB_AN2720=y
-+CONFIG_USB_KC2190=y
-+# CONFIG_USB_NET_ZAURUS is not set
-+CONFIG_USB_NET_CX82310_ETH=m
-+CONFIG_USB_NET_KALMIA=m
-+CONFIG_USB_NET_INT51X1=m
-+CONFIG_USB_IPHETH=m
-+CONFIG_USB_SIERRA_NET=m
-+CONFIG_USB_VL600=m
-+CONFIG_PPP=m
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_SLIP=m
-+CONFIG_SLIP_COMPRESSED=y
-+CONFIG_NETCONSOLE=m
-+CONFIG_INPUT_POLLDEV=m
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-+CONFIG_INPUT_JOYDEV=m
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_MISC=y
-+CONFIG_INPUT_AD714X=m
-+CONFIG_INPUT_ATI_REMOTE=m
-+CONFIG_INPUT_ATI_REMOTE2=m
-+CONFIG_INPUT_KEYSPAN_REMOTE=m
-+CONFIG_INPUT_POWERMATE=m
-+CONFIG_INPUT_YEALINK=m
-+CONFIG_INPUT_CM109=m
-+CONFIG_INPUT_UINPUT=m
-+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-+CONFIG_INPUT_ADXL34X=m
-+CONFIG_INPUT_CMA3000=m
-+CONFIG_SERIO=m
-+CONFIG_SERIO_RAW=m
-+CONFIG_GAMEPORT=m
-+CONFIG_GAMEPORT_NS558=m
-+CONFIG_GAMEPORT_L4=m
-+CONFIG_VT_HW_CONSOLE_BINDING=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_AMBA_PL011=y
-+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+# CONFIG_HW_RANDOM is not set
-+CONFIG_RAW_DRIVER=y
-+CONFIG_GPIO_SYSFS=y
-+# CONFIG_HWMON is not set
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2708_WDT=m
-+# CONFIG_MFD_SUPPORT is not set
-+CONFIG_FB=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SOUND_PRIME=m
-+CONFIG_HID_PID=y
-+CONFIG_USB_HIDDEV=y
-+CONFIG_HID_A4TECH=m
-+CONFIG_HID_ACRUX=m
-+CONFIG_HID_APPLE=m
-+CONFIG_HID_BELKIN=m
-+CONFIG_HID_CHERRY=m
-+CONFIG_HID_CHICONY=m
-+CONFIG_HID_CYPRESS=m
-+CONFIG_HID_DRAGONRISE=m
-+CONFIG_HID_EMS_FF=m
-+CONFIG_HID_ELECOM=m
-+CONFIG_HID_EZKEY=m
-+CONFIG_HID_HOLTEK=m
-+CONFIG_HID_KEYTOUCH=m
-+CONFIG_HID_KYE=m
-+CONFIG_HID_UCLOGIC=m
-+CONFIG_HID_WALTOP=m
-+CONFIG_HID_GYRATION=m
-+CONFIG_HID_TWINHAN=m
-+CONFIG_HID_KENSINGTON=m
-+CONFIG_HID_LCPOWER=m
-+CONFIG_HID_LOGITECH=m
-+CONFIG_HID_MAGICMOUSE=m
-+CONFIG_HID_MICROSOFT=m
-+CONFIG_HID_MONTEREY=m
-+CONFIG_HID_MULTITOUCH=m
-+CONFIG_HID_NTRIG=m
-+CONFIG_HID_ORTEK=m
-+CONFIG_HID_PANTHERLORD=m
-+CONFIG_HID_PETALYNX=m
-+CONFIG_HID_PICOLCD=m
-+CONFIG_HID_QUANTA=m
-+CONFIG_HID_ROCCAT=m
-+CONFIG_HID_SAMSUNG=m
-+CONFIG_HID_SONY=m
-+CONFIG_HID_SPEEDLINK=m
-+CONFIG_HID_SUNPLUS=m
-+CONFIG_HID_GREENASIA=m
-+CONFIG_HID_SMARTJOYPLUS=m
-+CONFIG_HID_TOPSEED=m
-+CONFIG_HID_THRUSTMASTER=m
-+CONFIG_HID_WACOM=m
-+CONFIG_HID_WIIMOTE=m
-+CONFIG_HID_ZEROPLUS=m
-+CONFIG_HID_ZYDACRON=m
-+CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_MON=m
-+CONFIG_USB_DWCOTG=y
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_STORAGE_REALTEK=m
-+CONFIG_USB_STORAGE_DATAFAB=m
-+CONFIG_USB_STORAGE_FREECOM=m
-+CONFIG_USB_STORAGE_ISD200=m
-+CONFIG_USB_STORAGE_USBAT=m
-+CONFIG_USB_STORAGE_SDDR09=m
-+CONFIG_USB_STORAGE_SDDR55=m
-+CONFIG_USB_STORAGE_JUMPSHOT=m
-+CONFIG_USB_STORAGE_ALAUDA=m
-+CONFIG_USB_STORAGE_ONETOUCH=m
-+CONFIG_USB_STORAGE_KARMA=m
-+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
-+CONFIG_USB_STORAGE_ENE_UB6250=m
-+CONFIG_USB_UAS=m
-+CONFIG_USB_LIBUSUAL=y
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_FUNSOFT=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_MOTOROLA=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_HP4X=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIEMENS_MPI=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_XIRCOM=m
-+CONFIG_USB_SERIAL_OPTION=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
-+CONFIG_USB_SERIAL_ZIO=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_EMI62=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_ADUTUX=m
-+CONFIG_USB_SEVSEG=m
-+CONFIG_USB_RIO500=m
-+CONFIG_USB_LEGOTOWER=m
-+CONFIG_USB_LCD=m
-+CONFIG_USB_LED=m
-+CONFIG_USB_CYPRESS_CY7C63=m
-+CONFIG_USB_CYTHERM=m
-+CONFIG_USB_IDMOUSE=m
-+CONFIG_USB_FTDI_ELAN=m
-+CONFIG_USB_APPLEDISPLAY=m
-+CONFIG_USB_LD=m
-+CONFIG_USB_TRANCEVIBRATOR=m
-+CONFIG_USB_IOWARRIOR=m
-+CONFIG_USB_TEST=m
-+CONFIG_USB_ISIGHTFW=m
-+CONFIG_USB_YUREX=m
-+CONFIG_MMC=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SDHCI_BCM2708=y
-+CONFIG_MMC_SDHCI_BCM2708_DMA=y
-+CONFIG_LEDS_GPIO=y
-+CONFIG_LEDS_TRIGGER_TIMER=m
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
-+CONFIG_UIO=m
-+CONFIG_UIO_PDRV=m
-+CONFIG_UIO_PDRV_GENIRQ=m
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_REISERFS_FS=m
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+CONFIG_JFS_SECURITY=y
-+CONFIG_XFS_FS=m
-+CONFIG_XFS_QUOTA=y
-+CONFIG_XFS_POSIX_ACL=y
-+CONFIG_XFS_RT=y
-+CONFIG_GFS2_FS=m
-+CONFIG_OCFS2_FS=m
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_NILFS2_FS=m
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FUSE_FS=m
-+CONFIG_CUSE=m
-+CONFIG_FSCACHE=y
-+CONFIG_CACHEFILES=y
-+CONFIG_ISO9660_FS=m
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_UDF_FS=m
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_NTFS_FS=m
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_CONFIGFS_FS=y
-+CONFIG_SQUASHFS=m
-+CONFIG_SQUASHFS_XATTR=y
-+CONFIG_SQUASHFS_LZO=y
-+CONFIG_SQUASHFS_XZ=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V3=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_CIFS=m
-+CONFIG_CIFS_WEAK_PW_HASH=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+CONFIG_9P_FS=m
-+CONFIG_PARTITION_ADVANCED=y
-+CONFIG_MAC_PARTITION=y
-+CONFIG_EFI_PARTITION=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
-+CONFIG_NLS_UTF8=m
-+# CONFIG_SCHED_DEBUG is not set
-+# CONFIG_DEBUG_BUGVERBOSE is not set
-+# CONFIG_FTRACE is not set
-+# CONFIG_ARM_UNWIND is not set
-+CONFIG_CRYPTO_AUTHENC=m
-+CONFIG_CRYPTO_SEQIV=m
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_HMAC=y
-+CONFIG_CRYPTO_XCBC=m
-+CONFIG_CRYPTO_MD5=y
-+CONFIG_CRYPTO_SHA1=y
-+CONFIG_CRYPTO_SHA256=m
-+CONFIG_CRYPTO_SHA512=m
-+CONFIG_CRYPTO_TGR192=m
-+CONFIG_CRYPTO_WP512=m
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_DES=y
-+CONFIG_CRYPTO_DEFLATE=m
-+# CONFIG_CRYPTO_ANSI_CPRNG is not set
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
-+CONFIG_I2C=y
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_COMPAT=y
-+CONFIG_I2C_CHARDEV=m
-+CONFIG_I2C_HELPER_AUTO=y
-+CONFIG_I2C_BCM2708=m
-+CONFIG_SPI=y
-+CONFIG_SPI_MASTER=y
-+CONFIG_SPI_BCM2708=m
-diff -Nur linux-3.11.10.orig/arch/arm/configs/bcmrpi_defconfig linux-3.11.10/arch/arm/configs/bcmrpi_defconfig
---- linux-3.11.10.orig/arch/arm/configs/bcmrpi_defconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/configs/bcmrpi_defconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,991 @@
-+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_FHANDLE=y
-+CONFIG_AUDIT=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_BSD_PROCESS_ACCT=y
-+CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_TASKSTATS=y
-+CONFIG_TASK_DELAY_ACCT=y
-+CONFIG_TASK_XACCT=y
-+CONFIG_TASK_IO_ACCOUNTING=y
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_CGROUP_FREEZER=y
-+CONFIG_CGROUP_DEVICE=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_RESOURCE_COUNTERS=y
-+CONFIG_BLK_CGROUP=y
-+CONFIG_NAMESPACES=y
-+CONFIG_SCHED_AUTOGROUP=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_COMPAT_BRK is not set
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+CONFIG_JUMP_LABEL=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+# CONFIG_BLK_DEV_BSG is not set
-+CONFIG_BLK_DEV_THROTTLING=y
-+CONFIG_PARTITION_ADVANCED=y
-+CONFIG_MAC_PARTITION=y
-+CONFIG_CFQ_GROUP_IOSCHED=y
-+CONFIG_ARCH_BCM2708=y
-+CONFIG_AEABI=y
-+CONFIG_SECCOMP=y
-+CONFIG_CC_STACKPROTECTOR=y
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
-+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext3 rootwait"
-+CONFIG_KEXEC=y
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_STAT=m
-+CONFIG_CPU_FREQ_STAT_DETAILS=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-+CONFIG_CPU_IDLE=y
-+CONFIG_VFP=y
-+CONFIG_BINFMT_MISC=m
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_UNIX=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
-+CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_SYN_COOKIES=y
-+CONFIG_INET_AH=m
-+CONFIG_INET_ESP=m
-+CONFIG_INET_IPCOMP=m
-+CONFIG_INET_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET_XFRM_MODE_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_BEET=m
-+CONFIG_INET_LRO=m
-+CONFIG_INET_DIAG=m
-+CONFIG_IPV6_PRIVACY=y
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+CONFIG_IPV6_MULTIPLE_TABLES=y
-+CONFIG_NETFILTER=y
-+CONFIG_NF_CONNTRACK=m
-+CONFIG_NF_CONNTRACK_ZONES=y
-+CONFIG_NF_CONNTRACK_EVENTS=y
-+CONFIG_NF_CONNTRACK_TIMESTAMP=y
-+CONFIG_NF_CT_PROTO_DCCP=m
-+CONFIG_NF_CT_PROTO_UDPLITE=m
-+CONFIG_NF_CONNTRACK_AMANDA=m
-+CONFIG_NF_CONNTRACK_FTP=m
-+CONFIG_NF_CONNTRACK_H323=m
-+CONFIG_NF_CONNTRACK_IRC=m
-+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-+CONFIG_NF_CONNTRACK_SNMP=m
-+CONFIG_NF_CONNTRACK_PPTP=m
-+CONFIG_NF_CONNTRACK_SANE=m
-+CONFIG_NF_CONNTRACK_SIP=m
-+CONFIG_NF_CONNTRACK_TFTP=m
-+CONFIG_NF_CT_NETLINK=m
-+CONFIG_NETFILTER_TPROXY=m
-+CONFIG_NETFILTER_XT_SET=m
-+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
-+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
-+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-+CONFIG_NETFILTER_XT_TARGET_DSCP=m
-+CONFIG_NETFILTER_XT_TARGET_HMARK=m
-+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
-+CONFIG_NETFILTER_XT_TARGET_LED=m
-+CONFIG_NETFILTER_XT_TARGET_LOG=m
-+CONFIG_NETFILTER_XT_TARGET_MARK=m
-+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-+CONFIG_NETFILTER_XT_TARGET_TEE=m
-+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-+CONFIG_NETFILTER_XT_TARGET_TRACE=m
-+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_BPF=m
-+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
-+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
-+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-+CONFIG_NETFILTER_XT_MATCH_CPU=m
-+CONFIG_NETFILTER_XT_MATCH_DCCP=m
-+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
-+CONFIG_NETFILTER_XT_MATCH_DSCP=m
-+CONFIG_NETFILTER_XT_MATCH_ESP=m
-+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_HELPER=m
-+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-+CONFIG_NETFILTER_XT_MATCH_MAC=m
-+CONFIG_NETFILTER_XT_MATCH_MARK=m
-+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
-+CONFIG_NETFILTER_XT_MATCH_OSF=m
-+CONFIG_NETFILTER_XT_MATCH_OWNER=m
-+CONFIG_NETFILTER_XT_MATCH_POLICY=m
-+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
-+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-+CONFIG_NETFILTER_XT_MATCH_REALM=m
-+CONFIG_NETFILTER_XT_MATCH_RECENT=m
-+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-+CONFIG_NETFILTER_XT_MATCH_STATE=m
-+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-+CONFIG_NETFILTER_XT_MATCH_STRING=m
-+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-+CONFIG_NETFILTER_XT_MATCH_TIME=m
-+CONFIG_NETFILTER_XT_MATCH_U32=m
-+CONFIG_IP_SET=m
-+CONFIG_IP_SET_BITMAP_IP=m
-+CONFIG_IP_SET_BITMAP_IPMAC=m
-+CONFIG_IP_SET_BITMAP_PORT=m
-+CONFIG_IP_SET_HASH_IP=m
-+CONFIG_IP_SET_HASH_IPPORT=m
-+CONFIG_IP_SET_HASH_IPPORTIP=m
-+CONFIG_IP_SET_HASH_IPPORTNET=m
-+CONFIG_IP_SET_HASH_NET=m
-+CONFIG_IP_SET_HASH_NETPORT=m
-+CONFIG_IP_SET_HASH_NETIFACE=m
-+CONFIG_IP_SET_LIST_SET=m
-+CONFIG_IP_VS=m
-+CONFIG_IP_VS_PROTO_TCP=y
-+CONFIG_IP_VS_PROTO_UDP=y
-+CONFIG_IP_VS_PROTO_ESP=y
-+CONFIG_IP_VS_PROTO_AH=y
-+CONFIG_IP_VS_PROTO_SCTP=y
-+CONFIG_IP_VS_RR=m
-+CONFIG_IP_VS_WRR=m
-+CONFIG_IP_VS_LC=m
-+CONFIG_IP_VS_WLC=m
-+CONFIG_IP_VS_LBLC=m
-+CONFIG_IP_VS_LBLCR=m
-+CONFIG_IP_VS_DH=m
-+CONFIG_IP_VS_SH=m
-+CONFIG_IP_VS_SED=m
-+CONFIG_IP_VS_NQ=m
-+CONFIG_IP_VS_FTP=m
-+CONFIG_IP_VS_PE_SIP=m
-+CONFIG_NF_CONNTRACK_IPV4=m
-+CONFIG_IP_NF_IPTABLES=m
-+CONFIG_IP_NF_MATCH_AH=m
-+CONFIG_IP_NF_MATCH_ECN=m
-+CONFIG_IP_NF_MATCH_TTL=m
-+CONFIG_IP_NF_FILTER=m
-+CONFIG_IP_NF_TARGET_REJECT=m
-+CONFIG_IP_NF_TARGET_ULOG=m
-+CONFIG_NF_NAT_IPV4=m
-+CONFIG_IP_NF_TARGET_MASQUERADE=m
-+CONFIG_IP_NF_TARGET_NETMAP=m
-+CONFIG_IP_NF_TARGET_REDIRECT=m
-+CONFIG_IP_NF_MANGLE=m
-+CONFIG_IP_NF_TARGET_ECN=m
-+CONFIG_IP_NF_TARGET_TTL=m
-+CONFIG_IP_NF_RAW=m
-+CONFIG_IP_NF_ARPTABLES=m
-+CONFIG_IP_NF_ARPFILTER=m
-+CONFIG_IP_NF_ARP_MANGLE=m
-+CONFIG_NF_CONNTRACK_IPV6=m
-+CONFIG_IP6_NF_IPTABLES=m
-+CONFIG_IP6_NF_MATCH_AH=m
-+CONFIG_IP6_NF_MATCH_EUI64=m
-+CONFIG_IP6_NF_MATCH_FRAG=m
-+CONFIG_IP6_NF_MATCH_OPTS=m
-+CONFIG_IP6_NF_MATCH_HL=m
-+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-+CONFIG_IP6_NF_MATCH_MH=m
-+CONFIG_IP6_NF_MATCH_RT=m
-+CONFIG_IP6_NF_TARGET_HL=m
-+CONFIG_IP6_NF_FILTER=m
-+CONFIG_IP6_NF_TARGET_REJECT=m
-+CONFIG_IP6_NF_MANGLE=m
-+CONFIG_IP6_NF_RAW=m
-+CONFIG_NF_NAT_IPV6=m
-+CONFIG_BRIDGE_NF_EBTABLES=m
-+CONFIG_BRIDGE_EBT_BROUTE=m
-+CONFIG_BRIDGE_EBT_T_FILTER=m
-+CONFIG_BRIDGE_EBT_T_NAT=m
-+CONFIG_BRIDGE_EBT_802_3=m
-+CONFIG_BRIDGE_EBT_AMONG=m
-+CONFIG_BRIDGE_EBT_ARP=m
-+CONFIG_BRIDGE_EBT_IP=m
-+CONFIG_BRIDGE_EBT_IP6=m
-+CONFIG_BRIDGE_EBT_LIMIT=m
-+CONFIG_BRIDGE_EBT_MARK=m
-+CONFIG_BRIDGE_EBT_PKTTYPE=m
-+CONFIG_BRIDGE_EBT_STP=m
-+CONFIG_BRIDGE_EBT_VLAN=m
-+CONFIG_BRIDGE_EBT_ARPREPLY=m
-+CONFIG_BRIDGE_EBT_DNAT=m
-+CONFIG_BRIDGE_EBT_MARK_T=m
-+CONFIG_BRIDGE_EBT_REDIRECT=m
-+CONFIG_BRIDGE_EBT_SNAT=m
-+CONFIG_BRIDGE_EBT_LOG=m
-+CONFIG_BRIDGE_EBT_ULOG=m
-+CONFIG_BRIDGE_EBT_NFLOG=m
-+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
-+CONFIG_L2TP=m
-+CONFIG_BRIDGE=m
-+CONFIG_VLAN_8021Q=m
-+CONFIG_VLAN_8021Q_GVRP=y
-+CONFIG_ATALK=m
-+CONFIG_NET_SCHED=y
-+CONFIG_NET_SCH_CBQ=m
-+CONFIG_NET_SCH_HTB=m
-+CONFIG_NET_SCH_HFSC=m
-+CONFIG_NET_SCH_PRIO=m
-+CONFIG_NET_SCH_MULTIQ=m
-+CONFIG_NET_SCH_RED=m
-+CONFIG_NET_SCH_SFB=m
-+CONFIG_NET_SCH_SFQ=m
-+CONFIG_NET_SCH_TEQL=m
-+CONFIG_NET_SCH_TBF=m
-+CONFIG_NET_SCH_GRED=m
-+CONFIG_NET_SCH_DSMARK=m
-+CONFIG_NET_SCH_NETEM=m
-+CONFIG_NET_SCH_DRR=m
-+CONFIG_NET_SCH_MQPRIO=m
-+CONFIG_NET_SCH_CHOKE=m
-+CONFIG_NET_SCH_QFQ=m
-+CONFIG_NET_SCH_CODEL=m
-+CONFIG_NET_SCH_FQ_CODEL=m
-+CONFIG_NET_SCH_INGRESS=m
-+CONFIG_NET_SCH_PLUG=m
-+CONFIG_NET_CLS_BASIC=m
-+CONFIG_NET_CLS_TCINDEX=m
-+CONFIG_NET_CLS_ROUTE4=m
-+CONFIG_NET_CLS_FW=m
-+CONFIG_NET_CLS_U32=m
-+CONFIG_CLS_U32_MARK=y
-+CONFIG_NET_CLS_RSVP=m
-+CONFIG_NET_CLS_RSVP6=m
-+CONFIG_NET_CLS_FLOW=m
-+CONFIG_NET_CLS_CGROUP=m
-+CONFIG_NET_EMATCH=y
-+CONFIG_NET_EMATCH_CMP=m
-+CONFIG_NET_EMATCH_NBYTE=m
-+CONFIG_NET_EMATCH_U32=m
-+CONFIG_NET_EMATCH_META=m
-+CONFIG_NET_EMATCH_TEXT=m
-+CONFIG_NET_EMATCH_IPSET=m
-+CONFIG_NET_CLS_ACT=y
-+CONFIG_NET_ACT_POLICE=m
-+CONFIG_NET_ACT_GACT=m
-+CONFIG_GACT_PROB=y
-+CONFIG_NET_ACT_MIRRED=m
-+CONFIG_NET_ACT_IPT=m
-+CONFIG_NET_ACT_NAT=m
-+CONFIG_NET_ACT_PEDIT=m
-+CONFIG_NET_ACT_SIMP=m
-+CONFIG_NET_ACT_SKBEDIT=m
-+CONFIG_NET_ACT_CSUM=m
-+CONFIG_BATMAN_ADV=m
-+CONFIG_OPENVSWITCH=m
-+CONFIG_NET_PKTGEN=m
-+CONFIG_HAMRADIO=y
-+CONFIG_AX25=m
-+CONFIG_NETROM=m
-+CONFIG_ROSE=m
-+CONFIG_MKISS=m
-+CONFIG_6PACK=m
-+CONFIG_BPQETHER=m
-+CONFIG_BAYCOM_SER_FDX=m
-+CONFIG_BAYCOM_SER_HDX=m
-+CONFIG_YAM=m
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRNET=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRTTY_SIR=m
-+CONFIG_KINGSUN_DONGLE=m
-+CONFIG_KSDAZZLE_DONGLE=m
-+CONFIG_KS959_DONGLE=m
-+CONFIG_USB_IRDA=m
-+CONFIG_SIGMATEL_FIR=m
-+CONFIG_MCS_FIR=m
-+CONFIG_BT=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIBCM203X=m
-+CONFIG_BT_HCIBPA10X=m
-+CONFIG_BT_HCIBFUSB=m
-+CONFIG_BT_HCIVHCI=m
-+CONFIG_BT_MRVL=m
-+CONFIG_BT_MRVL_SDIO=m
-+CONFIG_BT_ATH3K=m
-+CONFIG_BT_WILINK=m
-+CONFIG_CFG80211=m
-+CONFIG_CFG80211_WEXT=y
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_RC_PID=y
-+CONFIG_MAC80211_MESH=y
-+CONFIG_WIMAX=m
-+CONFIG_RFKILL=m
-+CONFIG_RFKILL_INPUT=y
-+CONFIG_NET_9P=m
-+CONFIG_NFC=m
-+CONFIG_NFC_PN533=m
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_CMA=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
-+CONFIG_BLK_DEV_DRBD=m
-+CONFIG_BLK_DEV_NBD=m
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_CDROM_PKTCDVD=m
-+CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
-+CONFIG_BLK_DEV_SD=m
-+CONFIG_BLK_DEV_SR=m
-+CONFIG_SCSI_MULTI_LUN=y
-+# CONFIG_SCSI_LOWLEVEL is not set
-+CONFIG_MD=y
-+CONFIG_NETDEVICES=y
-+CONFIG_DUMMY=m
-+CONFIG_NETCONSOLE=m
-+CONFIG_TUN=m
-+CONFIG_MDIO_BITBANG=m
-+CONFIG_PPP=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_SLIP=m
-+CONFIG_SLIP_COMPRESSED=y
-+CONFIG_USB_CATC=m
-+CONFIG_USB_KAWETH=m
-+CONFIG_USB_PEGASUS=m
-+CONFIG_USB_RTL8150=m
-+CONFIG_USB_RTL8152=m
-+CONFIG_USB_USBNET=y
-+CONFIG_USB_NET_AX8817X=m
-+CONFIG_USB_NET_CDCETHER=m
-+CONFIG_USB_NET_CDC_EEM=m
-+CONFIG_USB_NET_CDC_MBIM=m
-+CONFIG_USB_NET_DM9601=m
-+CONFIG_USB_NET_SMSC75XX=m
-+CONFIG_USB_NET_SMSC95XX=y
-+CONFIG_USB_NET_GL620A=m
-+CONFIG_USB_NET_NET1080=m
-+CONFIG_USB_NET_PLUSB=m
-+CONFIG_USB_NET_MCS7830=m
-+CONFIG_USB_NET_CDC_SUBSET=m
-+CONFIG_USB_ALI_M5632=y
-+CONFIG_USB_AN2720=y
-+CONFIG_USB_EPSON2888=y
-+CONFIG_USB_KC2190=y
-+CONFIG_USB_NET_ZAURUS=m
-+CONFIG_USB_NET_CX82310_ETH=m
-+CONFIG_USB_NET_KALMIA=m
-+CONFIG_USB_NET_QMI_WWAN=m
-+CONFIG_USB_NET_INT51X1=m
-+CONFIG_USB_IPHETH=m
-+CONFIG_USB_SIERRA_NET=m
-+CONFIG_USB_VL600=m
-+CONFIG_LIBERTAS_THINFIRM=m
-+CONFIG_LIBERTAS_THINFIRM_USB=m
-+CONFIG_AT76C50X_USB=m
-+CONFIG_USB_ZD1201=m
-+CONFIG_USB_NET_RNDIS_WLAN=m
-+CONFIG_RTL8187=m
-+CONFIG_MAC80211_HWSIM=m
-+CONFIG_ATH_CARDS=m
-+CONFIG_ATH9K=m
-+CONFIG_ATH9K_HTC=m
-+CONFIG_CARL9170=m
-+CONFIG_ATH6KL=m
-+CONFIG_ATH6KL_USB=m
-+CONFIG_AR5523=m
-+CONFIG_ATH10K=m
-+CONFIG_B43=m
-+# CONFIG_B43_PHY_N is not set
-+CONFIG_B43LEGACY=m
-+CONFIG_HOSTAP=m
-+CONFIG_LIBERTAS=m
-+CONFIG_LIBERTAS_USB=m
-+CONFIG_LIBERTAS_SDIO=m
-+CONFIG_P54_COMMON=m
-+CONFIG_P54_USB=m
-+CONFIG_RT2X00=m
-+CONFIG_RT2500USB=m
-+CONFIG_RT73USB=m
-+CONFIG_RT2800USB=m
-+CONFIG_RT2800USB_RT53XX=y
-+CONFIG_RT2800USB_UNKNOWN=y
-+CONFIG_RTL8192CU=m
-+CONFIG_ZD1211RW=m
-+CONFIG_MWIFIEX=m
-+CONFIG_MWIFIEX_SDIO=m
-+CONFIG_WIMAX_I2400M_USB=m
-+CONFIG_INPUT_POLLDEV=m
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-+CONFIG_INPUT_JOYDEV=m
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_JOYSTICK=y
-+CONFIG_JOYSTICK_IFORCE=m
-+CONFIG_JOYSTICK_IFORCE_USB=y
-+CONFIG_JOYSTICK_XPAD=m
-+CONFIG_JOYSTICK_XPAD_FF=y
-+CONFIG_INPUT_MISC=y
-+CONFIG_INPUT_AD714X=m
-+CONFIG_INPUT_ATI_REMOTE2=m
-+CONFIG_INPUT_KEYSPAN_REMOTE=m
-+CONFIG_INPUT_POWERMATE=m
-+CONFIG_INPUT_YEALINK=m
-+CONFIG_INPUT_CM109=m
-+CONFIG_INPUT_UINPUT=m
-+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-+CONFIG_INPUT_ADXL34X=m
-+CONFIG_INPUT_CMA3000=m
-+# CONFIG_SERIO is not set
-+CONFIG_VT_HW_CONSOLE_BINDING=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_AMBA_PL011=y
-+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+# CONFIG_HW_RANDOM is not set
-+CONFIG_RAW_DRIVER=y
-+CONFIG_BRCM_CHAR_DRIVERS=y
-+CONFIG_BCM_VC_CMA=y
-+CONFIG_I2C=y
-+CONFIG_I2C_CHARDEV=m
-+CONFIG_I2C_BCM2708=m
-+CONFIG_SPI=y
-+CONFIG_SPI_BCM2708=m
-+CONFIG_SPI_SPIDEV=m
-+CONFIG_GPIO_SYSFS=y
-+# CONFIG_HWMON is not set
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_BCM2835=y
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2708_WDT=m
-+CONFIG_MEDIA_SUPPORT=m
-+CONFIG_MEDIA_CAMERA_SUPPORT=y
-+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
-+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
-+CONFIG_MEDIA_RADIO_SUPPORT=y
-+CONFIG_MEDIA_RC_SUPPORT=y
-+CONFIG_MEDIA_CONTROLLER=y
-+CONFIG_LIRC=m
-+CONFIG_RC_DEVICES=y
-+CONFIG_RC_ATI_REMOTE=m
-+CONFIG_IR_IMON=m
-+CONFIG_IR_MCEUSB=m
-+CONFIG_IR_REDRAT3=m
-+CONFIG_IR_STREAMZAP=m
-+CONFIG_IR_IGUANA=m
-+CONFIG_IR_TTUSBIR=m
-+CONFIG_RC_LOOPBACK=m
-+CONFIG_IR_GPIO_CIR=m
-+CONFIG_MEDIA_USB_SUPPORT=y
-+CONFIG_USB_VIDEO_CLASS=m
-+CONFIG_USB_M5602=m
-+CONFIG_USB_STV06XX=m
-+CONFIG_USB_GL860=m
-+CONFIG_USB_GSPCA_BENQ=m
-+CONFIG_USB_GSPCA_CONEX=m
-+CONFIG_USB_GSPCA_CPIA1=m
-+CONFIG_USB_GSPCA_ETOMS=m
-+CONFIG_USB_GSPCA_FINEPIX=m
-+CONFIG_USB_GSPCA_JEILINJ=m
-+CONFIG_USB_GSPCA_JL2005BCD=m
-+CONFIG_USB_GSPCA_KINECT=m
-+CONFIG_USB_GSPCA_KONICA=m
-+CONFIG_USB_GSPCA_MARS=m
-+CONFIG_USB_GSPCA_MR97310A=m
-+CONFIG_USB_GSPCA_NW80X=m
-+CONFIG_USB_GSPCA_OV519=m
-+CONFIG_USB_GSPCA_OV534=m
-+CONFIG_USB_GSPCA_OV534_9=m
-+CONFIG_USB_GSPCA_PAC207=m
-+CONFIG_USB_GSPCA_PAC7302=m
-+CONFIG_USB_GSPCA_PAC7311=m
-+CONFIG_USB_GSPCA_SE401=m
-+CONFIG_USB_GSPCA_SN9C2028=m
-+CONFIG_USB_GSPCA_SN9C20X=m
-+CONFIG_USB_GSPCA_SONIXB=m
-+CONFIG_USB_GSPCA_SONIXJ=m
-+CONFIG_USB_GSPCA_SPCA500=m
-+CONFIG_USB_GSPCA_SPCA501=m
-+CONFIG_USB_GSPCA_SPCA505=m
-+CONFIG_USB_GSPCA_SPCA506=m
-+CONFIG_USB_GSPCA_SPCA508=m
-+CONFIG_USB_GSPCA_SPCA561=m
-+CONFIG_USB_GSPCA_SPCA1528=m
-+CONFIG_USB_GSPCA_SQ905=m
-+CONFIG_USB_GSPCA_SQ905C=m
-+CONFIG_USB_GSPCA_SQ930X=m
-+CONFIG_USB_GSPCA_STK014=m
-+CONFIG_USB_GSPCA_STV0680=m
-+CONFIG_USB_GSPCA_SUNPLUS=m
-+CONFIG_USB_GSPCA_T613=m
-+CONFIG_USB_GSPCA_TOPRO=m
-+CONFIG_USB_GSPCA_TV8532=m
-+CONFIG_USB_GSPCA_VC032X=m
-+CONFIG_USB_GSPCA_VICAM=m
-+CONFIG_USB_GSPCA_XIRLINK_CIT=m
-+CONFIG_USB_GSPCA_ZC3XX=m
-+CONFIG_USB_PWC=m
-+CONFIG_VIDEO_CPIA2=m
-+CONFIG_USB_ZR364XX=m
-+CONFIG_USB_STKWEBCAM=m
-+CONFIG_USB_S2255=m
-+CONFIG_USB_SN9C102=m
-+CONFIG_VIDEO_USBTV=m
-+CONFIG_VIDEO_PVRUSB2=m
-+CONFIG_VIDEO_HDPVR=m
-+CONFIG_VIDEO_TLG2300=m
-+CONFIG_VIDEO_USBVISION=m
-+CONFIG_VIDEO_STK1160=m
-+CONFIG_VIDEO_STK1160_AC97=y
-+CONFIG_VIDEO_AU0828=m
-+CONFIG_VIDEO_CX231XX=m
-+CONFIG_VIDEO_CX231XX_ALSA=m
-+CONFIG_VIDEO_CX231XX_DVB=m
-+CONFIG_VIDEO_TM6000=m
-+CONFIG_VIDEO_TM6000_ALSA=m
-+CONFIG_VIDEO_TM6000_DVB=m
-+CONFIG_DVB_USB=m
-+CONFIG_DVB_USB_A800=m
-+CONFIG_DVB_USB_DIBUSB_MB=m
-+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
-+CONFIG_DVB_USB_DIBUSB_MC=m
-+CONFIG_DVB_USB_DIB0700=m
-+CONFIG_DVB_USB_UMT_010=m
-+CONFIG_DVB_USB_CXUSB=m
-+CONFIG_DVB_USB_M920X=m
-+CONFIG_DVB_USB_DIGITV=m
-+CONFIG_DVB_USB_VP7045=m
-+CONFIG_DVB_USB_VP702X=m
-+CONFIG_DVB_USB_GP8PSK=m
-+CONFIG_DVB_USB_NOVA_T_USB2=m
-+CONFIG_DVB_USB_TTUSB2=m
-+CONFIG_DVB_USB_DTT200U=m
-+CONFIG_DVB_USB_OPERA1=m
-+CONFIG_DVB_USB_AF9005=m
-+CONFIG_DVB_USB_AF9005_REMOTE=m
-+CONFIG_DVB_USB_PCTV452E=m
-+CONFIG_DVB_USB_DW2102=m
-+CONFIG_DVB_USB_CINERGY_T2=m
-+CONFIG_DVB_USB_DTV5100=m
-+CONFIG_DVB_USB_FRIIO=m
-+CONFIG_DVB_USB_AZ6027=m
-+CONFIG_DVB_USB_TECHNISAT_USB2=m
-+CONFIG_DVB_USB_V2=m
-+CONFIG_DVB_USB_AF9015=m
-+CONFIG_DVB_USB_AF9035=m
-+CONFIG_DVB_USB_ANYSEE=m
-+CONFIG_DVB_USB_AU6610=m
-+CONFIG_DVB_USB_AZ6007=m
-+CONFIG_DVB_USB_CE6230=m
-+CONFIG_DVB_USB_EC168=m
-+CONFIG_DVB_USB_GL861=m
-+CONFIG_DVB_USB_IT913X=m
-+CONFIG_DVB_USB_LME2510=m
-+CONFIG_DVB_USB_MXL111SF=m
-+CONFIG_DVB_USB_RTL28XXU=m
-+CONFIG_SMS_USB_DRV=m
-+CONFIG_DVB_B2C2_FLEXCOP_USB=m
-+CONFIG_VIDEO_EM28XX=m
-+CONFIG_VIDEO_EM28XX_ALSA=m
-+CONFIG_VIDEO_EM28XX_DVB=m
-+CONFIG_RADIO_SI470X=y
-+CONFIG_USB_SI470X=m
-+CONFIG_USB_MR800=m
-+CONFIG_USB_DSBR=m
-+CONFIG_RADIO_SHARK=m
-+CONFIG_RADIO_SHARK2=m
-+CONFIG_RADIO_SI4713=m
-+CONFIG_USB_KEENE=m
-+CONFIG_USB_MA901=m
-+CONFIG_RADIO_SAA7706H=m
-+CONFIG_RADIO_TEF6862=m
-+CONFIG_RADIO_WL128X=m
-+CONFIG_FB=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SND_USB_HIFACE=m
-+CONFIG_SOUND_PRIME=m
-+CONFIG_HIDRAW=y
-+CONFIG_HID_A4TECH=m
-+CONFIG_HID_ACRUX=m
-+CONFIG_HID_APPLE=m
-+CONFIG_HID_BELKIN=m
-+CONFIG_HID_CHERRY=m
-+CONFIG_HID_CHICONY=m
-+CONFIG_HID_CYPRESS=m
-+CONFIG_HID_DRAGONRISE=m
-+CONFIG_HID_EMS_FF=m
-+CONFIG_HID_ELECOM=m
-+CONFIG_HID_ELO=m
-+CONFIG_HID_EZKEY=m
-+CONFIG_HID_HOLTEK=m
-+CONFIG_HID_KEYTOUCH=m
-+CONFIG_HID_KYE=m
-+CONFIG_HID_UCLOGIC=m
-+CONFIG_HID_WALTOP=m
-+CONFIG_HID_GYRATION=m
-+CONFIG_HID_TWINHAN=m
-+CONFIG_HID_KENSINGTON=m
-+CONFIG_HID_LCPOWER=m
-+CONFIG_HID_LOGITECH=m
-+CONFIG_HID_MAGICMOUSE=m
-+CONFIG_HID_MICROSOFT=m
-+CONFIG_HID_MONTEREY=m
-+CONFIG_HID_MULTITOUCH=m
-+CONFIG_HID_NTRIG=m
-+CONFIG_HID_ORTEK=m
-+CONFIG_HID_PANTHERLORD=m
-+CONFIG_HID_PETALYNX=m
-+CONFIG_HID_PICOLCD=m
-+CONFIG_HID_ROCCAT=m
-+CONFIG_HID_SAMSUNG=m
-+CONFIG_HID_SONY=m
-+CONFIG_HID_SPEEDLINK=m
-+CONFIG_HID_SUNPLUS=m
-+CONFIG_HID_GREENASIA=m
-+CONFIG_HID_SMARTJOYPLUS=m
-+CONFIG_HID_TOPSEED=m
-+CONFIG_HID_THINGM=m
-+CONFIG_HID_THRUSTMASTER=m
-+CONFIG_HID_WACOM=m
-+CONFIG_HID_WIIMOTE=m
-+CONFIG_HID_ZEROPLUS=m
-+CONFIG_HID_ZYDACRON=m
-+CONFIG_HID_PID=y
-+CONFIG_USB_HIDDEV=y
-+CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_MON=m
-+CONFIG_USB_DWCOTG=y
-+CONFIG_USB_PRINTER=m
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_STORAGE_REALTEK=m
-+CONFIG_USB_STORAGE_DATAFAB=m
-+CONFIG_USB_STORAGE_FREECOM=m
-+CONFIG_USB_STORAGE_ISD200=m
-+CONFIG_USB_STORAGE_USBAT=m
-+CONFIG_USB_STORAGE_SDDR09=m
-+CONFIG_USB_STORAGE_SDDR55=m
-+CONFIG_USB_STORAGE_JUMPSHOT=m
-+CONFIG_USB_STORAGE_ALAUDA=m
-+CONFIG_USB_STORAGE_ONETOUCH=m
-+CONFIG_USB_STORAGE_KARMA=m
-+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
-+CONFIG_USB_STORAGE_ENE_UB6250=m
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_FUNSOFT=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_F81232=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_METRO=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_MOTOROLA=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_HP4X=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIEMENS_MPI=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_XIRCOM=m
-+CONFIG_USB_SERIAL_OPTION=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
-+CONFIG_USB_SERIAL_XSENS_MT=m
-+CONFIG_USB_SERIAL_ZIO=m
-+CONFIG_USB_SERIAL_WISHBONE=m
-+CONFIG_USB_SERIAL_ZTE=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_QT2=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_EMI62=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_ADUTUX=m
-+CONFIG_USB_SEVSEG=m
-+CONFIG_USB_RIO500=m
-+CONFIG_USB_LEGOTOWER=m
-+CONFIG_USB_LCD=m
-+CONFIG_USB_LED=m
-+CONFIG_USB_CYPRESS_CY7C63=m
-+CONFIG_USB_CYTHERM=m
-+CONFIG_USB_IDMOUSE=m
-+CONFIG_USB_FTDI_ELAN=m
-+CONFIG_USB_APPLEDISPLAY=m
-+CONFIG_USB_LD=m
-+CONFIG_USB_TRANCEVIBRATOR=m
-+CONFIG_USB_IOWARRIOR=m
-+CONFIG_USB_TEST=m
-+CONFIG_USB_ISIGHTFW=m
-+CONFIG_USB_YUREX=m
-+CONFIG_MMC=y
-+CONFIG_MMC_BLOCK_MINORS=32
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SDHCI_BCM2708=y
-+CONFIG_MMC_SDHCI_BCM2708_DMA=y
-+CONFIG_LEDS_GPIO=m
-+CONFIG_LEDS_TRIGGER_TIMER=y
-+CONFIG_LEDS_TRIGGER_ONESHOT=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
-+CONFIG_LEDS_TRIGGER_CPU=y
-+CONFIG_LEDS_TRIGGER_GPIO=y
-+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-+CONFIG_LEDS_TRIGGER_TRANSIENT=m
-+CONFIG_LEDS_TRIGGER_CAMERA=m
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_DRV_DS1307=m
-+CONFIG_RTC_DRV_DS1374=m
-+CONFIG_RTC_DRV_DS1672=m
-+CONFIG_RTC_DRV_DS3232=m
-+CONFIG_RTC_DRV_MAX6900=m
-+CONFIG_RTC_DRV_RS5C372=m
-+CONFIG_RTC_DRV_ISL1208=m
-+CONFIG_RTC_DRV_ISL12022=m
-+CONFIG_RTC_DRV_X1205=m
-+CONFIG_RTC_DRV_PCF2127=m
-+CONFIG_RTC_DRV_PCF8523=m
-+CONFIG_RTC_DRV_PCF8563=m
-+CONFIG_RTC_DRV_PCF8583=m
-+CONFIG_RTC_DRV_M41T80=m
-+CONFIG_RTC_DRV_BQ32K=m
-+CONFIG_RTC_DRV_S35390A=m
-+CONFIG_RTC_DRV_FM3130=m
-+CONFIG_RTC_DRV_RX8581=m
-+CONFIG_RTC_DRV_RX8025=m
-+CONFIG_RTC_DRV_EM3027=m
-+CONFIG_RTC_DRV_RV3029C2=m
-+CONFIG_RTC_DRV_M41T93=m
-+CONFIG_RTC_DRV_M41T94=m
-+CONFIG_RTC_DRV_DS1305=m
-+CONFIG_RTC_DRV_DS1390=m
-+CONFIG_RTC_DRV_MAX6902=m
-+CONFIG_RTC_DRV_R9701=m
-+CONFIG_RTC_DRV_RS5C348=m
-+CONFIG_RTC_DRV_DS3234=m
-+CONFIG_RTC_DRV_PCF2123=m
-+CONFIG_RTC_DRV_RX4581=m
-+CONFIG_UIO=m
-+CONFIG_UIO_PDRV=m
-+CONFIG_UIO_PDRV_GENIRQ=m
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_REISERFS_FS=m
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+CONFIG_JFS_SECURITY=y
-+CONFIG_JFS_STATISTICS=y
-+CONFIG_XFS_FS=m
-+CONFIG_XFS_QUOTA=y
-+CONFIG_XFS_POSIX_ACL=y
-+CONFIG_XFS_RT=y
-+CONFIG_GFS2_FS=m
-+CONFIG_OCFS2_FS=m
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_NILFS2_FS=m
-+CONFIG_FANOTIFY=y
-+CONFIG_QFMT_V1=m
-+CONFIG_QFMT_V2=m
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FUSE_FS=m
-+CONFIG_CUSE=m
-+CONFIG_FSCACHE=y
-+CONFIG_FSCACHE_STATS=y
-+CONFIG_FSCACHE_HISTOGRAM=y
-+CONFIG_CACHEFILES=y
-+CONFIG_ISO9660_FS=m
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_UDF_FS=m
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_NTFS_FS=m
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_CONFIGFS_FS=y
-+CONFIG_SQUASHFS=m
-+CONFIG_SQUASHFS_XATTR=y
-+CONFIG_SQUASHFS_LZO=y
-+CONFIG_SQUASHFS_XZ=y
-+CONFIG_F2FS_FS=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_NFSD=m
-+CONFIG_NFSD_V3_ACL=y
-+CONFIG_NFSD_V4=y
-+CONFIG_CIFS=m
-+CONFIG_CIFS_WEAK_PW_HASH=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+CONFIG_9P_FS=m
-+CONFIG_9P_FS_POSIX_ACL=y
-+CONFIG_9P_FS_SECURITY=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
-+CONFIG_NLS_UTF8=m
-+CONFIG_DLM=m
-+CONFIG_PRINTK_TIME=y
-+CONFIG_BOOT_PRINTK_DELAY=y
-+CONFIG_DEBUG_INFO=y
-+CONFIG_DEBUG_STACK_USAGE=y
-+CONFIG_DEBUG_MEMORY_INIT=y
-+CONFIG_DETECT_HUNG_TASK=y
-+CONFIG_TIMER_STATS=y
-+CONFIG_LATENCYTOP=y
-+CONFIG_IRQSOFF_TRACER=y
-+CONFIG_SCHED_TRACER=y
-+CONFIG_STACK_TRACER=y
-+CONFIG_BLK_DEV_IO_TRACE=y
-+CONFIG_FUNCTION_PROFILER=y
-+CONFIG_KGDB=y
-+CONFIG_KGDB_KDB=y
-+CONFIG_KDB_KEYBOARD=y
-+CONFIG_STRICT_DEVMEM=y
-+CONFIG_CRYPTO_SEQIV=m
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_HMAC=y
-+CONFIG_CRYPTO_XCBC=m
-+CONFIG_CRYPTO_MD5=y
-+CONFIG_CRYPTO_SHA1=y
-+CONFIG_CRYPTO_SHA512=m
-+CONFIG_CRYPTO_TGR192=m
-+CONFIG_CRYPTO_WP512=m
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_DES=y
-+# CONFIG_CRYPTO_ANSI_CPRNG is not set
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
-diff -Nur linux-3.11.10.orig/arch/arm/configs/bcmrpi_emergency_defconfig linux-3.11.10/arch/arm/configs/bcmrpi_emergency_defconfig
---- linux-3.11.10.orig/arch/arm/configs/bcmrpi_emergency_defconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/configs/bcmrpi_emergency_defconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,532 @@
-+CONFIG_EXPERIMENTAL=y
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_BSD_PROCESS_ACCT=y
-+CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_FHANDLE=y
-+CONFIG_AUDIT=y
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_INITRAMFS_SOURCE="../target_fs"
-+CONFIG_CGROUP_FREEZER=y
-+CONFIG_CGROUP_DEVICE=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_RESOURCE_COUNTERS=y
-+CONFIG_BLK_CGROUP=y
-+CONFIG_NAMESPACES=y
-+CONFIG_SCHED_AUTOGROUP=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_COMPAT_BRK is not set
-+CONFIG_SLAB=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+# CONFIG_BLK_DEV_BSG is not set
-+CONFIG_BLK_DEV_THROTTLING=y
-+CONFIG_CFQ_GROUP_IOSCHED=y
-+CONFIG_ARCH_BCM2708=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_AEABI=y
-+CONFIG_SECCOMP=y
-+CONFIG_CC_STACKPROTECTOR=y
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
-+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext3 rootwait"
-+CONFIG_KEXEC=y
-+CONFIG_CPU_IDLE=y
-+CONFIG_VFP=y
-+CONFIG_BINFMT_MISC=m
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_UNIX=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
-+CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_SYN_COOKIES=y
-+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_BEET is not set
-+# CONFIG_INET_LRO is not set
-+# CONFIG_INET_DIAG is not set
-+# CONFIG_IPV6 is not set
-+CONFIG_NET_PKTGEN=m
-+CONFIG_IRDA=m
-+CONFIG_IRLAN=m
-+CONFIG_IRCOMM=m
-+CONFIG_IRDA_ULTRA=y
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+CONFIG_IRTTY_SIR=m
-+CONFIG_KINGSUN_DONGLE=m
-+CONFIG_KSDAZZLE_DONGLE=m
-+CONFIG_KS959_DONGLE=m
-+CONFIG_USB_IRDA=m
-+CONFIG_SIGMATEL_FIR=m
-+CONFIG_MCS_FIR=m
-+CONFIG_BT=m
-+CONFIG_BT_L2CAP=y
-+CONFIG_BT_SCO=y
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+CONFIG_BT_HCIBTUSB=m
-+CONFIG_BT_HCIBCM203X=m
-+CONFIG_BT_HCIBPA10X=m
-+CONFIG_BT_HCIBFUSB=m
-+CONFIG_BT_HCIVHCI=m
-+CONFIG_BT_MRVL=m
-+CONFIG_BT_MRVL_SDIO=m
-+CONFIG_BT_ATH3K=m
-+CONFIG_CFG80211=m
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_RC_PID=y
-+CONFIG_MAC80211_MESH=y
-+CONFIG_WIMAX=m
-+CONFIG_NET_9P=m
-+CONFIG_NFC=m
-+CONFIG_NFC_PN533=m
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
-+CONFIG_BLK_DEV_NBD=m
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_CDROM_PKTCDVD=m
-+CONFIG_MISC_DEVICES=y
-+CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
-+CONFIG_BLK_DEV_SD=y
-+CONFIG_BLK_DEV_SR=m
-+CONFIG_SCSI_MULTI_LUN=y
-+# CONFIG_SCSI_LOWLEVEL is not set
-+CONFIG_MD=y
-+CONFIG_NETDEVICES=y
-+CONFIG_TUN=m
-+CONFIG_PHYLIB=m
-+CONFIG_MDIO_BITBANG=m
-+CONFIG_NET_ETHERNET=y
-+# CONFIG_NETDEV_1000 is not set
-+# CONFIG_NETDEV_10000 is not set
-+CONFIG_LIBERTAS_THINFIRM=m
-+CONFIG_LIBERTAS_THINFIRM_USB=m
-+CONFIG_AT76C50X_USB=m
-+CONFIG_USB_ZD1201=m
-+CONFIG_USB_NET_RNDIS_WLAN=m
-+CONFIG_RTL8187=m
-+CONFIG_MAC80211_HWSIM=m
-+CONFIG_ATH_COMMON=m
-+CONFIG_ATH9K=m
-+CONFIG_ATH9K_HTC=m
-+CONFIG_CARL9170=m
-+CONFIG_B43=m
-+CONFIG_B43LEGACY=m
-+CONFIG_HOSTAP=m
-+CONFIG_IWM=m
-+CONFIG_LIBERTAS=m
-+CONFIG_LIBERTAS_USB=m
-+CONFIG_LIBERTAS_SDIO=m
-+CONFIG_P54_COMMON=m
-+CONFIG_P54_USB=m
-+CONFIG_RT2X00=m
-+CONFIG_RT2500USB=m
-+CONFIG_RT73USB=m
-+CONFIG_RT2800USB=m
-+CONFIG_RT2800USB_RT53XX=y
-+CONFIG_RTL8192CU=m
-+CONFIG_WL1251=m
-+CONFIG_WL12XX_MENU=m
-+CONFIG_ZD1211RW=m
-+CONFIG_MWIFIEX=m
-+CONFIG_MWIFIEX_SDIO=m
-+CONFIG_WIMAX_I2400M_USB=m
-+CONFIG_USB_CATC=m
-+CONFIG_USB_KAWETH=m
-+CONFIG_USB_PEGASUS=m
-+CONFIG_USB_RTL8150=m
-+CONFIG_USB_USBNET=y
-+CONFIG_USB_NET_AX8817X=m
-+CONFIG_USB_NET_CDCETHER=m
-+CONFIG_USB_NET_CDC_EEM=m
-+CONFIG_USB_NET_DM9601=m
-+CONFIG_USB_NET_SMSC75XX=m
-+CONFIG_USB_NET_SMSC95XX=y
-+CONFIG_USB_NET_GL620A=m
-+CONFIG_USB_NET_NET1080=m
-+CONFIG_USB_NET_PLUSB=m
-+CONFIG_USB_NET_MCS7830=m
-+CONFIG_USB_NET_CDC_SUBSET=m
-+CONFIG_USB_ALI_M5632=y
-+CONFIG_USB_AN2720=y
-+CONFIG_USB_KC2190=y
-+# CONFIG_USB_NET_ZAURUS is not set
-+CONFIG_USB_NET_CX82310_ETH=m
-+CONFIG_USB_NET_KALMIA=m
-+CONFIG_USB_NET_INT51X1=m
-+CONFIG_USB_IPHETH=m
-+CONFIG_USB_SIERRA_NET=m
-+CONFIG_USB_VL600=m
-+CONFIG_PPP=m
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_PPP_DEFLATE=m
-+CONFIG_PPP_BSDCOMP=m
-+CONFIG_SLIP=m
-+CONFIG_SLIP_COMPRESSED=y
-+CONFIG_NETCONSOLE=m
-+CONFIG_INPUT_POLLDEV=m
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-+CONFIG_INPUT_JOYDEV=m
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_MISC=y
-+CONFIG_INPUT_AD714X=m
-+CONFIG_INPUT_ATI_REMOTE=m
-+CONFIG_INPUT_ATI_REMOTE2=m
-+CONFIG_INPUT_KEYSPAN_REMOTE=m
-+CONFIG_INPUT_POWERMATE=m
-+CONFIG_INPUT_YEALINK=m
-+CONFIG_INPUT_CM109=m
-+CONFIG_INPUT_UINPUT=m
-+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-+CONFIG_INPUT_ADXL34X=m
-+CONFIG_INPUT_CMA3000=m
-+CONFIG_SERIO=m
-+CONFIG_SERIO_RAW=m
-+CONFIG_GAMEPORT=m
-+CONFIG_GAMEPORT_NS558=m
-+CONFIG_GAMEPORT_L4=m
-+CONFIG_VT_HW_CONSOLE_BINDING=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_AMBA_PL011=y
-+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+# CONFIG_HW_RANDOM is not set
-+CONFIG_RAW_DRIVER=y
-+CONFIG_GPIO_SYSFS=y
-+# CONFIG_HWMON is not set
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2708_WDT=m
-+# CONFIG_MFD_SUPPORT is not set
-+CONFIG_FB=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SOUND_PRIME=m
-+CONFIG_HID_PID=y
-+CONFIG_USB_HIDDEV=y
-+CONFIG_HID_A4TECH=m
-+CONFIG_HID_ACRUX=m
-+CONFIG_HID_APPLE=m
-+CONFIG_HID_BELKIN=m
-+CONFIG_HID_CHERRY=m
-+CONFIG_HID_CHICONY=m
-+CONFIG_HID_CYPRESS=m
-+CONFIG_HID_DRAGONRISE=m
-+CONFIG_HID_EMS_FF=m
-+CONFIG_HID_ELECOM=m
-+CONFIG_HID_EZKEY=m
-+CONFIG_HID_HOLTEK=m
-+CONFIG_HID_KEYTOUCH=m
-+CONFIG_HID_KYE=m
-+CONFIG_HID_UCLOGIC=m
-+CONFIG_HID_WALTOP=m
-+CONFIG_HID_GYRATION=m
-+CONFIG_HID_TWINHAN=m
-+CONFIG_HID_KENSINGTON=m
-+CONFIG_HID_LCPOWER=m
-+CONFIG_HID_LOGITECH=m
-+CONFIG_HID_MAGICMOUSE=m
-+CONFIG_HID_MICROSOFT=m
-+CONFIG_HID_MONTEREY=m
-+CONFIG_HID_MULTITOUCH=m
-+CONFIG_HID_NTRIG=m
-+CONFIG_HID_ORTEK=m
-+CONFIG_HID_PANTHERLORD=m
-+CONFIG_HID_PETALYNX=m
-+CONFIG_HID_PICOLCD=m
-+CONFIG_HID_QUANTA=m
-+CONFIG_HID_ROCCAT=m
-+CONFIG_HID_SAMSUNG=m
-+CONFIG_HID_SONY=m
-+CONFIG_HID_SPEEDLINK=m
-+CONFIG_HID_SUNPLUS=m
-+CONFIG_HID_GREENASIA=m
-+CONFIG_HID_SMARTJOYPLUS=m
-+CONFIG_HID_TOPSEED=m
-+CONFIG_HID_THRUSTMASTER=m
-+CONFIG_HID_WACOM=m
-+CONFIG_HID_WIIMOTE=m
-+CONFIG_HID_ZEROPLUS=m
-+CONFIG_HID_ZYDACRON=m
-+CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_MON=m
-+CONFIG_USB_DWCOTG=y
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_STORAGE_REALTEK=m
-+CONFIG_USB_STORAGE_DATAFAB=m
-+CONFIG_USB_STORAGE_FREECOM=m
-+CONFIG_USB_STORAGE_ISD200=m
-+CONFIG_USB_STORAGE_USBAT=m
-+CONFIG_USB_STORAGE_SDDR09=m
-+CONFIG_USB_STORAGE_SDDR55=m
-+CONFIG_USB_STORAGE_JUMPSHOT=m
-+CONFIG_USB_STORAGE_ALAUDA=m
-+CONFIG_USB_STORAGE_ONETOUCH=m
-+CONFIG_USB_STORAGE_KARMA=m
-+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
-+CONFIG_USB_STORAGE_ENE_UB6250=m
-+CONFIG_USB_UAS=y
-+CONFIG_USB_LIBUSUAL=y
-+CONFIG_USB_MDC800=m
-+CONFIG_USB_MICROTEK=m
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_FUNSOFT=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_MOTOROLA=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_HP4X=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIEMENS_MPI=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_XIRCOM=m
-+CONFIG_USB_SERIAL_OPTION=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
-+CONFIG_USB_SERIAL_ZIO=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_EMI62=m
-+CONFIG_USB_EMI26=m
-+CONFIG_USB_ADUTUX=m
-+CONFIG_USB_SEVSEG=m
-+CONFIG_USB_RIO500=m
-+CONFIG_USB_LEGOTOWER=m
-+CONFIG_USB_LCD=m
-+CONFIG_USB_LED=m
-+CONFIG_USB_CYPRESS_CY7C63=m
-+CONFIG_USB_CYTHERM=m
-+CONFIG_USB_IDMOUSE=m
-+CONFIG_USB_FTDI_ELAN=m
-+CONFIG_USB_APPLEDISPLAY=m
-+CONFIG_USB_LD=m
-+CONFIG_USB_TRANCEVIBRATOR=m
-+CONFIG_USB_IOWARRIOR=m
-+CONFIG_USB_TEST=m
-+CONFIG_USB_ISIGHTFW=m
-+CONFIG_USB_YUREX=m
-+CONFIG_MMC=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SDHCI_BCM2708=y
-+CONFIG_MMC_SDHCI_BCM2708_DMA=y
-+CONFIG_LEDS_GPIO=y
-+CONFIG_LEDS_TRIGGER_TIMER=m
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
-+CONFIG_UIO=m
-+CONFIG_UIO_PDRV=m
-+CONFIG_UIO_PDRV_GENIRQ=m
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_REISERFS_FS=m
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+CONFIG_JFS_SECURITY=y
-+CONFIG_JFS_STATISTICS=y
-+CONFIG_XFS_FS=m
-+CONFIG_XFS_QUOTA=y
-+CONFIG_XFS_POSIX_ACL=y
-+CONFIG_XFS_RT=y
-+CONFIG_GFS2_FS=m
-+CONFIG_OCFS2_FS=m
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_NILFS2_FS=m
-+CONFIG_FANOTIFY=y
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FUSE_FS=m
-+CONFIG_CUSE=m
-+CONFIG_FSCACHE=y
-+CONFIG_FSCACHE_STATS=y
-+CONFIG_FSCACHE_HISTOGRAM=y
-+CONFIG_CACHEFILES=y
-+CONFIG_ISO9660_FS=m
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_UDF_FS=m
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_NTFS_FS=m
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_CONFIGFS_FS=y
-+CONFIG_SQUASHFS=m
-+CONFIG_SQUASHFS_XATTR=y
-+CONFIG_SQUASHFS_LZO=y
-+CONFIG_SQUASHFS_XZ=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V3=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_CIFS=m
-+CONFIG_CIFS_WEAK_PW_HASH=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+CONFIG_9P_FS=m
-+CONFIG_9P_FS_POSIX_ACL=y
-+CONFIG_PARTITION_ADVANCED=y
-+CONFIG_MAC_PARTITION=y
-+CONFIG_EFI_PARTITION=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
-+CONFIG_NLS_UTF8=m
-+CONFIG_PRINTK_TIME=y
-+CONFIG_DETECT_HUNG_TASK=y
-+CONFIG_TIMER_STATS=y
-+CONFIG_DEBUG_STACK_USAGE=y
-+CONFIG_DEBUG_INFO=y
-+CONFIG_DEBUG_MEMORY_INIT=y
-+CONFIG_BOOT_PRINTK_DELAY=y
-+CONFIG_LATENCYTOP=y
-+CONFIG_SYSCTL_SYSCALL_CHECK=y
-+CONFIG_IRQSOFF_TRACER=y
-+CONFIG_SCHED_TRACER=y
-+CONFIG_STACK_TRACER=y
-+CONFIG_BLK_DEV_IO_TRACE=y
-+CONFIG_FUNCTION_PROFILER=y
-+CONFIG_KGDB=y
-+CONFIG_KGDB_KDB=y
-+CONFIG_KDB_KEYBOARD=y
-+CONFIG_STRICT_DEVMEM=y
-+CONFIG_CRYPTO_AUTHENC=m
-+CONFIG_CRYPTO_SEQIV=m
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_HMAC=y
-+CONFIG_CRYPTO_XCBC=m
-+CONFIG_CRYPTO_MD5=y
-+CONFIG_CRYPTO_SHA1=y
-+CONFIG_CRYPTO_SHA256=m
-+CONFIG_CRYPTO_SHA512=m
-+CONFIG_CRYPTO_TGR192=m
-+CONFIG_CRYPTO_WP512=m
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_DES=y
-+CONFIG_CRYPTO_DEFLATE=m
-+# CONFIG_CRYPTO_ANSI_CPRNG is not set
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
-diff -Nur linux-3.11.10.orig/arch/arm/configs/bcmrpi_quick_defconfig linux-3.11.10/arch/arm/configs/bcmrpi_quick_defconfig
---- linux-3.11.10.orig/arch/arm/configs/bcmrpi_quick_defconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/configs/bcmrpi_quick_defconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,197 @@
-+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-+CONFIG_LOCALVERSION="-quick"
-+# CONFIG_LOCALVERSION_AUTO is not set
-+# CONFIG_SWAP is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_KALLSYMS_ALL=y
-+CONFIG_EMBEDDED=y
-+CONFIG_PERF_EVENTS=y
-+# CONFIG_COMPAT_BRK is not set
-+CONFIG_SLAB=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+# CONFIG_BLK_DEV_BSG is not set
-+CONFIG_ARCH_BCM2708=y
-+CONFIG_PREEMPT=y
-+CONFIG_AEABI=y
-+CONFIG_UACCESS_WITH_MEMCPY=y
-+CONFIG_ZBOOT_ROM_TEXT=0x0
-+CONFIG_ZBOOT_ROM_BSS=0x0
-+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-+CONFIG_CPU_IDLE=y
-+CONFIG_VFP=y
-+CONFIG_BINFMT_MISC=y
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_UNIX=y
-+CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_SYN_COOKIES=y
-+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_BEET is not set
-+# CONFIG_INET_LRO is not set
-+# CONFIG_INET_DIAG is not set
-+# CONFIG_IPV6 is not set
-+# CONFIG_WIRELESS is not set
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_SCSI=y
-+# CONFIG_SCSI_PROC_FS is not set
-+# CONFIG_SCSI_LOWLEVEL is not set
-+CONFIG_NETDEVICES=y
-+# CONFIG_NET_VENDOR_BROADCOM is not set
-+# CONFIG_NET_VENDOR_CIRRUS is not set
-+# CONFIG_NET_VENDOR_FARADAY is not set
-+# CONFIG_NET_VENDOR_INTEL is not set
-+# CONFIG_NET_VENDOR_MARVELL is not set
-+# CONFIG_NET_VENDOR_MICREL is not set
-+# CONFIG_NET_VENDOR_NATSEMI is not set
-+# CONFIG_NET_VENDOR_SEEQ is not set
-+# CONFIG_NET_VENDOR_STMICRO is not set
-+# CONFIG_NET_VENDOR_WIZNET is not set
-+CONFIG_USB_USBNET=y
-+# CONFIG_USB_NET_AX8817X is not set
-+# CONFIG_USB_NET_CDCETHER is not set
-+# CONFIG_USB_NET_CDC_NCM is not set
-+CONFIG_USB_NET_SMSC95XX=y
-+# CONFIG_USB_NET_NET1080 is not set
-+# CONFIG_USB_NET_CDC_SUBSET is not set
-+# CONFIG_USB_NET_ZAURUS is not set
-+# CONFIG_WLAN is not set
-+# CONFIG_INPUT_MOUSEDEV is not set
-+CONFIG_INPUT_EVDEV=y
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+# CONFIG_SERIO is not set
-+CONFIG_VT_HW_CONSOLE_BINDING=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_DEVKMEM is not set
-+CONFIG_SERIAL_AMBA_PL011=y
-+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-+CONFIG_TTY_PRINTK=y
-+CONFIG_HW_RANDOM=y
-+CONFIG_HW_RANDOM_BCM2708=y
-+CONFIG_RAW_DRIVER=y
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_BCM2835=y
-+CONFIG_WATCHDOG=y
-+CONFIG_BCM2708_WDT=y
-+CONFIG_REGULATOR=y
-+CONFIG_REGULATOR_DEBUG=y
-+CONFIG_REGULATOR_FIXED_VOLTAGE=y
-+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
-+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
-+CONFIG_FB=y
-+CONFIG_FB_BCM2708=y
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=y
-+CONFIG_SND_BCM2835=y
-+# CONFIG_SND_USB is not set
-+CONFIG_USB=y
-+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-+CONFIG_USB_DWCOTG=y
-+CONFIG_MMC=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SDHCI_BCM2708=y
-+CONFIG_MMC_SDHCI_BCM2708_DMA=y
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=y
-+CONFIG_LEDS_TRIGGERS=y
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_AUTOFS4_FS=y
-+CONFIG_FSCACHE=y
-+CONFIG_CACHEFILES=y
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_CONFIGFS_FS=y
-+# CONFIG_MISC_FILESYSTEMS is not set
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V3_ACL=y
-+CONFIG_NFS_V4=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_NFS_FSCACHE=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=y
-+CONFIG_NLS_CODEPAGE_775=y
-+CONFIG_NLS_CODEPAGE_850=y
-+CONFIG_NLS_CODEPAGE_852=y
-+CONFIG_NLS_CODEPAGE_855=y
-+CONFIG_NLS_CODEPAGE_857=y
-+CONFIG_NLS_CODEPAGE_860=y
-+CONFIG_NLS_CODEPAGE_861=y
-+CONFIG_NLS_CODEPAGE_862=y
-+CONFIG_NLS_CODEPAGE_863=y
-+CONFIG_NLS_CODEPAGE_864=y
-+CONFIG_NLS_CODEPAGE_865=y
-+CONFIG_NLS_CODEPAGE_866=y
-+CONFIG_NLS_CODEPAGE_869=y
-+CONFIG_NLS_CODEPAGE_936=y
-+CONFIG_NLS_CODEPAGE_950=y
-+CONFIG_NLS_CODEPAGE_932=y
-+CONFIG_NLS_CODEPAGE_949=y
-+CONFIG_NLS_CODEPAGE_874=y
-+CONFIG_NLS_ISO8859_8=y
-+CONFIG_NLS_CODEPAGE_1250=y
-+CONFIG_NLS_CODEPAGE_1251=y
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=y
-+CONFIG_NLS_ISO8859_2=y
-+CONFIG_NLS_ISO8859_3=y
-+CONFIG_NLS_ISO8859_4=y
-+CONFIG_NLS_ISO8859_5=y
-+CONFIG_NLS_ISO8859_6=y
-+CONFIG_NLS_ISO8859_7=y
-+CONFIG_NLS_ISO8859_9=y
-+CONFIG_NLS_ISO8859_13=y
-+CONFIG_NLS_ISO8859_14=y
-+CONFIG_NLS_ISO8859_15=y
-+CONFIG_NLS_UTF8=y
-+CONFIG_PRINTK_TIME=y
-+CONFIG_DEBUG_FS=y
-+CONFIG_DETECT_HUNG_TASK=y
-+# CONFIG_DEBUG_PREEMPT is not set
-+# CONFIG_DEBUG_BUGVERBOSE is not set
-+# CONFIG_FTRACE is not set
-+CONFIG_KGDB=y
-+CONFIG_KGDB_KDB=y
-+# CONFIG_ARM_UNWIND is not set
-+CONFIG_CRYPTO_CBC=y
-+CONFIG_CRYPTO_HMAC=y
-+CONFIG_CRYPTO_MD5=y
-+CONFIG_CRYPTO_SHA1=y
-+CONFIG_CRYPTO_DES=y
-+# CONFIG_CRYPTO_ANSI_CPRNG is not set
-+# CONFIG_CRYPTO_HW is not set
-+CONFIG_CRC_ITU_T=y
-+CONFIG_LIBCRC32C=y
-diff -Nur linux-3.11.10.orig/arch/arm/include/asm/fiq.h linux-3.11.10/arch/arm/include/asm/fiq.h
---- linux-3.11.10.orig/arch/arm/include/asm/fiq.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/include/asm/fiq.h 2014-02-07 19:57:28.000000000 +0100
-@@ -42,6 +42,7 @@
- /* helpers defined in fiqasm.S: */
- extern void __set_fiq_regs(unsigned long const *regs);
- extern void __get_fiq_regs(unsigned long *regs);
-+extern void __FIQ_Branch(unsigned long *regs);
-
- static inline void set_fiq_regs(struct pt_regs const *regs)
- {
-diff -Nur linux-3.11.10.orig/arch/arm/Kconfig linux-3.11.10/arch/arm/Kconfig
---- linux-3.11.10.orig/arch/arm/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -366,6 +366,23 @@
- This enables support for systems based on Atmel
- AT91RM9200 and AT91SAM9* processors.
-
-+config ARCH_BCM2708
-+ bool "Broadcom BCM2708 family"
-+ select CPU_V6
-+ select ARM_AMBA
-+ select HAVE_CLK
-+ select HAVE_SCHED_CLOCK
-+ select NEED_MACH_MEMORY_H
-+ select CLKDEV_LOOKUP
-+ select ARCH_HAS_CPUFREQ
-+ select GENERIC_CLOCKEVENTS
-+ select ARM_ERRATA_411920
-+ select MACH_BCM2708
-+ select VC4
-+ select FIQ
-+ help
-+ This enables support for Broadcom BCM2708 boards.
-+
- config ARCH_CLPS711X
- bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
- select ARCH_REQUIRE_GPIOLIB
-@@ -1041,6 +1058,7 @@
- source "arch/arm/mach-vt8500/Kconfig"
-
- source "arch/arm/mach-w90x900/Kconfig"
-+source "arch/arm/mach-bcm2708/Kconfig"
-
- source "arch/arm/mach-zynq/Kconfig"
-
-diff -Nur linux-3.11.10.orig/arch/arm/Kconfig.debug linux-3.11.10/arch/arm/Kconfig.debug
---- linux-3.11.10.orig/arch/arm/Kconfig.debug 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/Kconfig.debug 2014-02-07 19:57:28.000000000 +0100
-@@ -610,6 +610,14 @@
- For more details about semihosting, please see
- chapter 8 of DUI0203I_rvct_developer_guide.pdf from ARM Ltd.
-
-+ config DEBUG_BCM2708_UART0
-+ bool "Broadcom BCM2708 UART0 (PL011)"
-+ depends on MACH_BCM2708
-+ help
-+ Say Y here if you want the debug print routines to direct
-+ their output to UART 0. The port must have been initialised
-+ by the boot-loader before use.
-+
- endchoice
-
- config DEBUG_EXYNOS_UART
-diff -Nur linux-3.11.10.orig/arch/arm/kernel/fiqasm.S linux-3.11.10/arch/arm/kernel/fiqasm.S
---- linux-3.11.10.orig/arch/arm/kernel/fiqasm.S 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/kernel/fiqasm.S 2014-02-07 19:57:28.000000000 +0100
-@@ -25,6 +25,9 @@
- ENTRY(__set_fiq_regs)
- mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
- mrs r1, cpsr
-+@@@@@@@@@@@@@@@ hack: enable the fiq here to keep usb driver happy
-+ and r1, #~PSR_F_BIT
-+@@@@@@@@@@@@@@@ endhack: (need to find better place for this to happen)
- msr cpsr_c, r2 @ select FIQ mode
- mov r0, r0 @ avoid hazard prior to ARMv4
- ldmia r0!, {r8 - r12}
-@@ -47,3 +50,7 @@
- mov r0, r0 @ avoid hazard prior to ARMv4
- mov pc, lr
- ENDPROC(__get_fiq_regs)
-+
-+ENTRY(__FIQ_Branch)
-+ mov pc, r8
-+ENDPROC(__FIQ_Branch)
-diff -Nur linux-3.11.10.orig/arch/arm/kernel/fiq.c linux-3.11.10/arch/arm/kernel/fiq.c
---- linux-3.11.10.orig/arch/arm/kernel/fiq.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/kernel/fiq.c 2014-02-07 19:57:28.000000000 +0100
-@@ -142,6 +142,7 @@
- EXPORT_SYMBOL(set_fiq_handler);
- EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */
- EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */
-+EXPORT_SYMBOL(__FIQ_Branch); /* defined in fiqasm.S */
- EXPORT_SYMBOL(claim_fiq);
- EXPORT_SYMBOL(release_fiq);
- EXPORT_SYMBOL(enable_fiq);
-diff -Nur linux-3.11.10.orig/arch/arm/kernel/process.c linux-3.11.10/arch/arm/kernel/process.c
---- linux-3.11.10.orig/arch/arm/kernel/process.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/kernel/process.c 2014-02-07 19:57:28.000000000 +0100
-@@ -176,6 +176,16 @@
- default_idle();
- }
-
-+char bcm2708_reboot_mode = 'h';
-+
-+int __init reboot_setup(char *str)
-+{
-+ bcm2708_reboot_mode = str[0];
-+ return 1;
-+}
-+
-+__setup("reboot=", reboot_setup);
-+
- /*
- * Called by kexec, immediately prior to machine_kexec().
- *
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/armctrl.c linux-3.11.10/arch/arm/mach-bcm2708/armctrl.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/armctrl.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/armctrl.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,219 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/armctrl.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/io.h>
-+#include <linux/version.h>
-+#include <linux/syscore_ops.h>
-+#include <linux/interrupt.h>
-+
-+#include <asm/mach/irq.h>
-+#include <mach/hardware.h>
-+#include "armctrl.h"
-+
-+/* For support of kernels >= 3.0 assume only one VIC for now*/
-+static unsigned int remap_irqs[(INTERRUPT_ARASANSDIO + 1) - INTERRUPT_JPEG] = {
-+ INTERRUPT_VC_JPEG,
-+ INTERRUPT_VC_USB,
-+ INTERRUPT_VC_3D,
-+ INTERRUPT_VC_DMA2,
-+ INTERRUPT_VC_DMA3,
-+ INTERRUPT_VC_I2C,
-+ INTERRUPT_VC_SPI,
-+ INTERRUPT_VC_I2SPCM,
-+ INTERRUPT_VC_SDIO,
-+ INTERRUPT_VC_UART,
-+ INTERRUPT_VC_ARASANSDIO
-+};
-+
-+static void armctrl_mask_irq(struct irq_data *d)
-+{
-+ static const unsigned int disables[4] = {
-+ ARM_IRQ_DIBL1,
-+ ARM_IRQ_DIBL2,
-+ ARM_IRQ_DIBL3,
-+ 0
-+ };
-+
-+ if (d->irq >= FIQ_START) {
-+ writel(0, __io_address(ARM_IRQ_FAST));
-+ } else {
-+ unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
-+ writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3]));
-+ }
-+}
-+
-+static void armctrl_unmask_irq(struct irq_data *d)
-+{
-+ static const unsigned int enables[4] = {
-+ ARM_IRQ_ENBL1,
-+ ARM_IRQ_ENBL2,
-+ ARM_IRQ_ENBL3,
-+ 0
-+ };
-+
-+ if (d->irq >= FIQ_START) {
-+ unsigned int data =
-+ (unsigned int)irq_get_chip_data(d->irq) - FIQ_START;
-+ writel(0x80 | data, __io_address(ARM_IRQ_FAST));
-+ } else {
-+ unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
-+ writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3]));
-+ }
-+}
-+
-+#if defined(CONFIG_PM)
-+
-+/* for kernels 3.xx use the new syscore_ops apis but for older kernels use the sys dev class */
-+
-+/* Static defines
-+ * struct armctrl_device - VIC PM device (< 3.xx)
-+ * @sysdev: The system device which is registered. (< 3.xx)
-+ * @irq: The IRQ number for the base of the VIC.
-+ * @base: The register base for the VIC.
-+ * @resume_sources: A bitmask of interrupts for resume.
-+ * @resume_irqs: The IRQs enabled for resume.
-+ * @int_select: Save for VIC_INT_SELECT.
-+ * @int_enable: Save for VIC_INT_ENABLE.
-+ * @soft_int: Save for VIC_INT_SOFT.
-+ * @protect: Save for VIC_PROTECT.
-+ */
-+struct armctrl_info {
-+ void __iomem *base;
-+ int irq;
-+ u32 resume_sources;
-+ u32 resume_irqs;
-+ u32 int_select;
-+ u32 int_enable;
-+ u32 soft_int;
-+ u32 protect;
-+} armctrl;
-+
-+static int armctrl_suspend(void)
-+{
-+ return 0;
-+}
-+
-+static void armctrl_resume(void)
-+{
-+ return;
-+}
-+
-+/**
-+ * armctrl_pm_register - Register a VIC for later power management control
-+ * @base: The base address of the VIC.
-+ * @irq: The base IRQ for the VIC.
-+ * @resume_sources: bitmask of interrupts allowed for resume sources.
-+ *
-+ * For older kernels (< 3.xx) do -
-+ * Register the VIC with the system device tree so that it can be notified
-+ * of suspend and resume requests and ensure that the correct actions are
-+ * taken to re-instate the settings on resume.
-+ */
-+static void __init armctrl_pm_register(void __iomem * base, unsigned int irq,
-+ u32 resume_sources)
-+{
-+ armctrl.base = base;
-+ armctrl.resume_sources = resume_sources;
-+ armctrl.irq = irq;
-+}
-+
-+static int armctrl_set_wake(struct irq_data *d, unsigned int on)
-+{
-+ unsigned int off = d->irq & 31;
-+ u32 bit = 1 << off;
-+
-+ if (!(bit & armctrl.resume_sources))
-+ return -EINVAL;
-+
-+ if (on)
-+ armctrl.resume_irqs |= bit;
-+ else
-+ armctrl.resume_irqs &= ~bit;
-+
-+ return 0;
-+}
-+
-+#else
-+static inline void armctrl_pm_register(void __iomem * base, unsigned int irq,
-+ u32 arg1)
-+{
-+}
-+
-+#define armctrl_suspend NULL
-+#define armctrl_resume NULL
-+#define armctrl_set_wake NULL
-+#endif /* CONFIG_PM */
-+
-+static struct syscore_ops armctrl_syscore_ops = {
-+ .suspend = armctrl_suspend,
-+ .resume = armctrl_resume,
-+};
-+
-+/**
-+ * armctrl_syscore_init - initicall to register VIC pm functions
-+ *
-+ * This is called via late_initcall() to register
-+ * the resources for the VICs due to the early
-+ * nature of the VIC's registration.
-+*/
-+static int __init armctrl_syscore_init(void)
-+{
-+ register_syscore_ops(&armctrl_syscore_ops);
-+ return 0;
-+}
-+
-+late_initcall(armctrl_syscore_init);
-+
-+static struct irq_chip armctrl_chip = {
-+ .name = "ARMCTRL",
-+ .irq_ack = armctrl_mask_irq,
-+ .irq_mask = armctrl_mask_irq,
-+ .irq_unmask = armctrl_unmask_irq,
-+ .irq_set_wake = armctrl_set_wake,
-+};
-+
-+/**
-+ * armctrl_init - initialise a vectored interrupt controller
-+ * @base: iomem base address
-+ * @irq_start: starting interrupt number, must be muliple of 32
-+ * @armctrl_sources: bitmask of interrupt sources to allow
-+ * @resume_sources: bitmask of interrupt sources to allow for resume
-+ */
-+int __init armctrl_init(void __iomem * base, unsigned int irq_start,
-+ u32 armctrl_sources, u32 resume_sources)
-+{
-+ unsigned int irq;
-+
-+ for (irq = 0; irq < NR_IRQS; irq++) {
-+ unsigned int data = irq;
-+ if (irq >= INTERRUPT_JPEG && irq <= INTERRUPT_ARASANSDIO)
-+ data = remap_irqs[irq - INTERRUPT_JPEG];
-+
-+ irq_set_chip(irq, &armctrl_chip);
-+ irq_set_chip_data(irq, (void *)data);
-+ irq_set_handler(irq, handle_level_irq);
-+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_DISABLED);
-+ }
-+
-+ armctrl_pm_register(base, irq_start, resume_sources);
-+ init_FIQ(FIQ_START);
-+ return 0;
-+}
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/armctrl.h linux-3.11.10/arch/arm/mach-bcm2708/armctrl.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/armctrl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/armctrl.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,27 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/armctrl.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef __BCM2708_ARMCTRL_H
-+#define __BCM2708_ARMCTRL_H
-+
-+extern int __init armctrl_init(void __iomem * base, unsigned int irq_start,
-+ u32 armctrl_sources, u32 resume_sources);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/bcm2708.c linux-3.11.10/arch/arm/mach-bcm2708/bcm2708.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/bcm2708.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/bcm2708.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,917 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/bcm2708.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/serial_8250.h>
-+#include <linux/platform_device.h>
-+#include <linux/syscore_ops.h>
-+#include <linux/interrupt.h>
-+#include <linux/amba/bus.h>
-+#include <linux/amba/clcd.h>
-+#include <linux/clockchips.h>
-+#include <linux/cnt32_to_63.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/spi/spi.h>
-+#include <linux/w1-gpio.h>
-+
-+#include <linux/version.h>
-+#include <linux/clkdev.h>
-+#include <asm/system.h>
-+#include <mach/hardware.h>
-+#include <asm/irq.h>
-+#include <linux/leds.h>
-+#include <asm/mach-types.h>
-+#include <asm/sched_clock.h>
-+
-+#include <asm/mach/arch.h>
-+#include <asm/mach/flash.h>
-+#include <asm/mach/irq.h>
-+#include <asm/mach/time.h>
-+#include <asm/mach/map.h>
-+
-+#include <mach/timex.h>
-+#include <mach/dma.h>
-+#include <mach/vcio.h>
-+#include <mach/system.h>
-+
-+#include <linux/delay.h>
-+
-+#include "bcm2708.h"
-+#include "armctrl.h"
-+#include "clock.h"
-+
-+#ifdef CONFIG_BCM_VC_CMA
-+#include <linux/broadcom/vc_cma.h>
-+#endif
-+
-+
-+/* Effectively we have an IOMMU (ARM<->VideoCore map) that is set up to
-+ * give us IO access only to 64Mbytes of physical memory (26 bits). We could
-+ * represent this window by setting our dmamasks to 26 bits but, in fact
-+ * we're not going to use addresses outside this range (they're not in real
-+ * memory) so we don't bother.
-+ *
-+ * In the future we might include code to use this IOMMU to remap other
-+ * physical addresses onto VideoCore memory then the use of 32-bits would be
-+ * more legitimate.
-+ */
-+#define DMA_MASK_BITS_COMMON 32
-+
-+// use GPIO 4 for the one-wire GPIO pin, if enabled
-+#define W1_GPIO 4
-+
-+/* command line parameters */
-+static unsigned boardrev, serial;
-+static unsigned uart_clock;
-+static unsigned reboot_part = 0;
-+
-+static void __init bcm2708_init_led(void);
-+
-+void __init bcm2708_init_irq(void)
-+{
-+ armctrl_init(__io_address(ARMCTRL_IC_BASE), 0, 0, 0);
-+}
-+
-+static struct map_desc bcm2708_io_desc[] __initdata = {
-+ {
-+ .virtual = IO_ADDRESS(ARMCTRL_BASE),
-+ .pfn = __phys_to_pfn(ARMCTRL_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(UART0_BASE),
-+ .pfn = __phys_to_pfn(UART0_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(UART1_BASE),
-+ .pfn = __phys_to_pfn(UART1_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(DMA_BASE),
-+ .pfn = __phys_to_pfn(DMA_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(MCORE_BASE),
-+ .pfn = __phys_to_pfn(MCORE_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(ST_BASE),
-+ .pfn = __phys_to_pfn(ST_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(USB_BASE),
-+ .pfn = __phys_to_pfn(USB_BASE),
-+ .length = SZ_128K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(PM_BASE),
-+ .pfn = __phys_to_pfn(PM_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE},
-+ {
-+ .virtual = IO_ADDRESS(GPIO_BASE),
-+ .pfn = __phys_to_pfn(GPIO_BASE),
-+ .length = SZ_4K,
-+ .type = MT_DEVICE}
-+};
-+
-+void __init bcm2708_map_io(void)
-+{
-+ iotable_init(bcm2708_io_desc, ARRAY_SIZE(bcm2708_io_desc));
-+}
-+
-+/* The STC is a free running counter that increments at the rate of 1MHz */
-+#define STC_FREQ_HZ 1000000
-+
-+static inline uint32_t timer_read(void)
-+{
-+ /* STC: a free running counter that increments at the rate of 1MHz */
-+ return readl(__io_address(ST_BASE + 0x04));
-+}
-+
-+static unsigned long bcm2708_read_current_timer(void)
-+{
-+ return timer_read();
-+}
-+
-+static u32 notrace bcm2708_read_sched_clock(void)
-+{
-+ return timer_read();
-+}
-+
-+static cycle_t clksrc_read(struct clocksource *cs)
-+{
-+ return timer_read();
-+}
-+
-+static struct clocksource clocksource_stc = {
-+ .name = "stc",
-+ .rating = 300,
-+ .read = clksrc_read,
-+ .mask = CLOCKSOURCE_MASK(32),
-+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-+};
-+
-+unsigned long frc_clock_ticks32(void)
-+{
-+ return timer_read();
-+}
-+
-+static void __init bcm2708_clocksource_init(void)
-+{
-+ if (clocksource_register_hz(&clocksource_stc, STC_FREQ_HZ)) {
-+ printk(KERN_ERR "timer: failed to initialize clock "
-+ "source %s\n", clocksource_stc.name);
-+ }
-+}
-+
-+
-+/*
-+ * These are fixed clocks.
-+ */
-+static struct clk ref24_clk = {
-+ .rate = UART0_CLOCK, /* The UART is clocked at 3MHz via APB_CLK */
-+};
-+
-+static struct clk osc_clk = {
-+#ifdef CONFIG_ARCH_BCM2708_CHIPIT
-+ .rate = 27000000,
-+#else
-+ .rate = 500000000, /* ARM clock is set from the VideoCore booter */
-+#endif
-+};
-+
-+/* warning - the USB needs a clock > 34MHz */
-+
-+static struct clk sdhost_clk = {
-+#ifdef CONFIG_ARCH_BCM2708_CHIPIT
-+ .rate = 4000000, /* 4MHz */
-+#else
-+ .rate = 250000000, /* 250MHz */
-+#endif
-+};
-+
-+static struct clk_lookup lookups[] = {
-+ { /* UART0 */
-+ .dev_id = "dev:f1",
-+ .clk = &ref24_clk,
-+ },
-+ { /* USB */
-+ .dev_id = "bcm2708_usb",
-+ .clk = &osc_clk,
-+ }, { /* SPI */
-+ .dev_id = "bcm2708_spi.0",
-+ .clk = &sdhost_clk,
-+ }, { /* BSC0 */
-+ .dev_id = "bcm2708_i2c.0",
-+ .clk = &sdhost_clk,
-+ }, { /* BSC1 */
-+ .dev_id = "bcm2708_i2c.1",
-+ .clk = &sdhost_clk,
-+ }
-+};
-+
-+#define UART0_IRQ { IRQ_UART, 0 /*NO_IRQ*/ }
-+#define UART0_DMA { 15, 14 }
-+
-+AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);
-+
-+static struct amba_device *amba_devs[] __initdata = {
-+ &uart0_device,
-+};
-+
-+static struct resource bcm2708_dmaman_resources[] = {
-+ {
-+ .start = DMA_BASE,
-+ .end = DMA_BASE + SZ_4K - 1,
-+ .flags = IORESOURCE_MEM,
-+ }
-+};
-+
-+static struct platform_device bcm2708_dmaman_device = {
-+ .name = BCM_DMAMAN_DRIVER_NAME,
-+ .id = 0, /* first bcm2708_dma */
-+ .resource = bcm2708_dmaman_resources,
-+ .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources),
-+};
-+
-+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
-+static struct w1_gpio_platform_data w1_gpio_pdata = {
-+ .pin = W1_GPIO,
-+ .is_open_drain = 0,
-+};
-+
-+static struct platform_device w1_device = {
-+ .name = "w1-gpio",
-+ .id = -1,
-+ .dev.platform_data = &w1_gpio_pdata,
-+};
-+#endif
-+
-+static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-+
-+static struct platform_device bcm2708_fb_device = {
-+ .name = "bcm2708_fb",
-+ .id = -1, /* only one bcm2708_fb */
-+ .resource = NULL,
-+ .num_resources = 0,
-+ .dev = {
-+ .dma_mask = &fb_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
-+ },
-+};
-+
-+static struct plat_serial8250_port bcm2708_uart1_platform_data[] = {
-+ {
-+ .mapbase = UART1_BASE + 0x40,
-+ .irq = IRQ_AUX,
-+ .uartclk = 125000000,
-+ .regshift = 2,
-+ .iotype = UPIO_MEM,
-+ .flags = UPF_FIXED_TYPE | UPF_IOREMAP | UPF_SKIP_TEST,
-+ .type = PORT_8250,
-+ },
-+ {},
-+};
-+
-+static struct platform_device bcm2708_uart1_device = {
-+ .name = "serial8250",
-+ .id = PLAT8250_DEV_PLATFORM,
-+ .dev = {
-+ .platform_data = bcm2708_uart1_platform_data,
-+ },
-+};
-+
-+static struct resource bcm2708_usb_resources[] = {
-+ [0] = {
-+ .start = USB_BASE,
-+ .end = USB_BASE + SZ_128K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = MPHI_BASE,
-+ .end = MPHI_BASE + SZ_4K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [2] = {
-+ .start = IRQ_HOSTPORT,
-+ .end = IRQ_HOSTPORT,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+bool fiq_fix_enable = true;
-+
-+static struct resource bcm2708_usb_resources_no_fiq_fix[] = {
-+ [0] = {
-+ .start = USB_BASE,
-+ .end = USB_BASE + SZ_128K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = IRQ_USB,
-+ .end = IRQ_USB,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-+
-+static struct platform_device bcm2708_usb_device = {
-+ .name = "bcm2708_usb",
-+ .id = -1, /* only one bcm2708_usb */
-+ .resource = bcm2708_usb_resources,
-+ .num_resources = ARRAY_SIZE(bcm2708_usb_resources),
-+ .dev = {
-+ .dma_mask = &usb_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
-+ },
-+};
-+
-+static struct resource bcm2708_vcio_resources[] = {
-+ [0] = { /* mailbox/semaphore/doorbell access */
-+ .start = MCORE_BASE,
-+ .end = MCORE_BASE + SZ_4K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+};
-+
-+static u64 vcio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-+
-+static struct platform_device bcm2708_vcio_device = {
-+ .name = BCM_VCIO_DRIVER_NAME,
-+ .id = -1, /* only one VideoCore I/O area */
-+ .resource = bcm2708_vcio_resources,
-+ .num_resources = ARRAY_SIZE(bcm2708_vcio_resources),
-+ .dev = {
-+ .dma_mask = &vcio_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
-+ },
-+};
-+
-+#ifdef CONFIG_BCM2708_GPIO
-+#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
-+
-+static struct resource bcm2708_gpio_resources[] = {
-+ [0] = { /* general purpose I/O */
-+ .start = GPIO_BASE,
-+ .end = GPIO_BASE + SZ_4K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+};
-+
-+static u64 gpio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-+
-+static struct platform_device bcm2708_gpio_device = {
-+ .name = BCM_GPIO_DRIVER_NAME,
-+ .id = -1, /* only one VideoCore I/O area */
-+ .resource = bcm2708_gpio_resources,
-+ .num_resources = ARRAY_SIZE(bcm2708_gpio_resources),
-+ .dev = {
-+ .dma_mask = &gpio_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
-+ },
-+};
-+#endif
-+
-+static struct resource bcm2708_systemtimer_resources[] = {
-+ [0] = { /* system timer access */
-+ .start = ST_BASE,
-+ .end = ST_BASE + SZ_4K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .start = IRQ_TIMER3,
-+ .end = IRQ_TIMER3,
-+ .flags = IORESOURCE_IRQ,
-+ }
-+
-+};
-+
-+static u64 systemtimer_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-+
-+static struct platform_device bcm2708_systemtimer_device = {
-+ .name = "bcm2708_systemtimer",
-+ .id = -1, /* only one VideoCore I/O area */
-+ .resource = bcm2708_systemtimer_resources,
-+ .num_resources = ARRAY_SIZE(bcm2708_systemtimer_resources),
-+ .dev = {
-+ .dma_mask = &systemtimer_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
-+ },
-+};
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708 /* Arasan emmc SD */
-+static struct resource bcm2708_emmc_resources[] = {
-+ [0] = {
-+ .start = EMMC_BASE,
-+ .end = EMMC_BASE + SZ_256 - 1, /* we only need this area */
-+ /* the memory map actually makes SZ_4K available */
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = IRQ_ARASANSDIO,
-+ .end = IRQ_ARASANSDIO,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static u64 bcm2708_emmc_dmamask = 0xffffffffUL;
-+
-+struct platform_device bcm2708_emmc_device = {
-+ .name = "bcm2708_sdhci",
-+ .id = 0,
-+ .num_resources = ARRAY_SIZE(bcm2708_emmc_resources),
-+ .resource = bcm2708_emmc_resources,
-+ .dev = {
-+ .dma_mask = &bcm2708_emmc_dmamask,
-+ .coherent_dma_mask = 0xffffffffUL},
-+};
-+#endif /* CONFIG_MMC_SDHCI_BCM2708 */
-+
-+static struct resource bcm2708_powerman_resources[] = {
-+ [0] = {
-+ .start = PM_BASE,
-+ .end = PM_BASE + SZ_256 - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+};
-+
-+static u64 powerman_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-+
-+struct platform_device bcm2708_powerman_device = {
-+ .name = "bcm2708_powerman",
-+ .id = 0,
-+ .num_resources = ARRAY_SIZE(bcm2708_powerman_resources),
-+ .resource = bcm2708_powerman_resources,
-+ .dev = {
-+ .dma_mask = &powerman_dmamask,
-+ .coherent_dma_mask = 0xffffffffUL},
-+};
-+
-+
-+static struct platform_device bcm2708_alsa_devices[] = {
-+ [0] = {
-+ .name = "bcm2835_AUD0",
-+ .id = 0, /* first audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [1] = {
-+ .name = "bcm2835_AUD1",
-+ .id = 1, /* second audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [2] = {
-+ .name = "bcm2835_AUD2",
-+ .id = 2, /* third audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [3] = {
-+ .name = "bcm2835_AUD3",
-+ .id = 3, /* forth audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [4] = {
-+ .name = "bcm2835_AUD4",
-+ .id = 4, /* fifth audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [5] = {
-+ .name = "bcm2835_AUD5",
-+ .id = 5, /* sixth audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [6] = {
-+ .name = "bcm2835_AUD6",
-+ .id = 6, /* seventh audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+ [7] = {
-+ .name = "bcm2835_AUD7",
-+ .id = 7, /* eighth audio device */
-+ .resource = 0,
-+ .num_resources = 0,
-+ },
-+};
-+
-+static struct resource bcm2708_spi_resources[] = {
-+ {
-+ .start = SPI0_BASE,
-+ .end = SPI0_BASE + SZ_256 - 1,
-+ .flags = IORESOURCE_MEM,
-+ }, {
-+ .start = IRQ_SPI,
-+ .end = IRQ_SPI,
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+
-+static struct platform_device bcm2708_spi_device = {
-+ .name = "bcm2708_spi",
-+ .id = 0,
-+ .num_resources = ARRAY_SIZE(bcm2708_spi_resources),
-+ .resource = bcm2708_spi_resources,
-+};
-+
-+#ifdef CONFIG_BCM2708_SPIDEV
-+static struct spi_board_info bcm2708_spi_devices[] = {
-+#ifdef CONFIG_SPI_SPIDEV
-+ {
-+ .modalias = "spidev",
-+ .max_speed_hz = 500000,
-+ .bus_num = 0,
-+ .chip_select = 0,
-+ .mode = SPI_MODE_0,
-+ }, {
-+ .modalias = "spidev",
-+ .max_speed_hz = 500000,
-+ .bus_num = 0,
-+ .chip_select = 1,
-+ .mode = SPI_MODE_0,
-+ }
-+#endif
-+};
-+#endif
-+
-+static struct resource bcm2708_bsc0_resources[] = {
-+ {
-+ .start = BSC0_BASE,
-+ .end = BSC0_BASE + SZ_256 - 1,
-+ .flags = IORESOURCE_MEM,
-+ }, {
-+ .start = INTERRUPT_I2C,
-+ .end = INTERRUPT_I2C,
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct platform_device bcm2708_bsc0_device = {
-+ .name = "bcm2708_i2c",
-+ .id = 0,
-+ .num_resources = ARRAY_SIZE(bcm2708_bsc0_resources),
-+ .resource = bcm2708_bsc0_resources,
-+};
-+
-+
-+static struct resource bcm2708_bsc1_resources[] = {
-+ {
-+ .start = BSC1_BASE,
-+ .end = BSC1_BASE + SZ_256 - 1,
-+ .flags = IORESOURCE_MEM,
-+ }, {
-+ .start = INTERRUPT_I2C,
-+ .end = INTERRUPT_I2C,
-+ .flags = IORESOURCE_IRQ,
-+ }
-+};
-+
-+static struct platform_device bcm2708_bsc1_device = {
-+ .name = "bcm2708_i2c",
-+ .id = 1,
-+ .num_resources = ARRAY_SIZE(bcm2708_bsc1_resources),
-+ .resource = bcm2708_bsc1_resources,
-+};
-+
-+static struct platform_device bcm2835_hwmon_device = {
-+ .name = "bcm2835_hwmon",
-+};
-+
-+static struct platform_device bcm2835_thermal_device = {
-+ .name = "bcm2835_thermal",
-+};
-+
-+int __init bcm_register_device(struct platform_device *pdev)
-+{
-+ int ret;
-+
-+ ret = platform_device_register(pdev);
-+ if (ret)
-+ pr_debug("Unable to register platform device '%s': %d\n",
-+ pdev->name, ret);
-+
-+ return ret;
-+}
-+
-+int calc_rsts(int partition)
-+{
-+ return PM_PASSWORD |
-+ ((partition & (1 << 0)) << 0) |
-+ ((partition & (1 << 1)) << 1) |
-+ ((partition & (1 << 2)) << 2) |
-+ ((partition & (1 << 3)) << 3) |
-+ ((partition & (1 << 4)) << 4) |
-+ ((partition & (1 << 5)) << 5);
-+}
-+
-+static void bcm2708_restart(enum reboot_mode mode, const char *cmd)
-+{
-+ extern char bcm2708_reboot_mode;
-+ uint32_t pm_rstc, pm_wdog;
-+ uint32_t timeout = 10;
-+ uint32_t pm_rsts = 0;
-+
-+ if(bcm2708_reboot_mode == 'q')
-+ {
-+ // NOOBS < 1.3 booting with reboot=q
-+ pm_rsts = readl(__io_address(PM_RSTS));
-+ pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRQ_SET;
-+ }
-+ else if(bcm2708_reboot_mode == 'p')
-+ {
-+ // NOOBS < 1.3 halting
-+ pm_rsts = readl(__io_address(PM_RSTS));
-+ pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRH_SET;
-+ }
-+ else
-+ {
-+ pm_rsts = calc_rsts(reboot_part);
-+ }
-+
-+ writel(pm_rsts, __io_address(PM_RSTS));
-+
-+ /* Setup watchdog for reset */
-+ pm_rstc = readl(__io_address(PM_RSTC));
-+
-+ pm_wdog = PM_PASSWORD | (timeout & PM_WDOG_TIME_SET); // watchdog timer = timer clock / 16; need password (31:16) + value (11:0)
-+ pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET;
-+
-+ writel(pm_wdog, __io_address(PM_WDOG));
-+ writel(pm_rstc, __io_address(PM_RSTC));
-+}
-+
-+/* We can't really power off, but if we do the normal reset scheme, and indicate to bootcode.bin not to reboot, then most of the chip will be powered off */
-+static void bcm2708_power_off(void)
-+{
-+ extern char bcm2708_reboot_mode;
-+ if(bcm2708_reboot_mode == 'q')
-+ {
-+ // NOOBS < v1.3
-+ bcm2708_restart('p', "");
-+ }
-+ else
-+ {
-+ /* partition 63 is special code for HALT the bootloader knows not to boot*/
-+ reboot_part = 63;
-+ /* continue with normal reset mechanism */
-+ bcm2708_restart(0, "");
-+ }
-+}
-+
-+void __init bcm2708_init(void)
-+{
-+ int i;
-+
-+#if defined(CONFIG_BCM_VC_CMA)
-+ vc_cma_early_init();
-+#endif
-+ printk("bcm2708.uart_clock = %d\n", uart_clock);
-+ pm_power_off = bcm2708_power_off;
-+
-+ if (uart_clock)
-+ lookups[0].clk->rate = uart_clock;
-+
-+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
-+ clkdev_add(&lookups[i]);
-+
-+ bcm_register_device(&bcm2708_dmaman_device);
-+ bcm_register_device(&bcm2708_vcio_device);
-+#ifdef CONFIG_BCM2708_GPIO
-+ bcm_register_device(&bcm2708_gpio_device);
-+#endif
-+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
-+ platform_device_register(&w1_device);
-+#endif
-+ bcm_register_device(&bcm2708_systemtimer_device);
-+ bcm_register_device(&bcm2708_fb_device);
-+ if (!fiq_fix_enable)
-+ {
-+ bcm2708_usb_device.resource = bcm2708_usb_resources_no_fiq_fix;
-+ bcm2708_usb_device.num_resources = ARRAY_SIZE(bcm2708_usb_resources_no_fiq_fix);
-+ }
-+ bcm_register_device(&bcm2708_usb_device);
-+ bcm_register_device(&bcm2708_uart1_device);
-+ bcm_register_device(&bcm2708_powerman_device);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708
-+ bcm_register_device(&bcm2708_emmc_device);
-+#endif
-+ bcm2708_init_led();
-+ for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
-+ bcm_register_device(&bcm2708_alsa_devices[i]);
-+
-+ bcm_register_device(&bcm2708_spi_device);
-+ bcm_register_device(&bcm2708_bsc0_device);
-+ bcm_register_device(&bcm2708_bsc1_device);
-+
-+ bcm_register_device(&bcm2835_hwmon_device);
-+ bcm_register_device(&bcm2835_thermal_device);
-+
-+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
-+ struct amba_device *d = amba_devs[i];
-+ amba_device_register(d, &iomem_resource);
-+ }
-+ system_rev = boardrev;
-+ system_serial_low = serial;
-+
-+#ifdef CONFIG_BCM2708_SPIDEV
-+ spi_register_board_info(bcm2708_spi_devices,
-+ ARRAY_SIZE(bcm2708_spi_devices));
-+#endif
-+}
-+
-+static void timer_set_mode(enum clock_event_mode mode,
-+ struct clock_event_device *clk)
-+{
-+ switch (mode) {
-+ case CLOCK_EVT_MODE_ONESHOT: /* Leave the timer disabled, .set_next_event will enable it */
-+ case CLOCK_EVT_MODE_SHUTDOWN:
-+ break;
-+ case CLOCK_EVT_MODE_PERIODIC:
-+
-+ case CLOCK_EVT_MODE_UNUSED:
-+ case CLOCK_EVT_MODE_RESUME:
-+
-+ default:
-+ printk(KERN_ERR "timer_set_mode: unhandled mode:%d\n",
-+ (int)mode);
-+ break;
-+ }
-+
-+}
-+
-+static int timer_set_next_event(unsigned long cycles,
-+ struct clock_event_device *unused)
-+{
-+ unsigned long stc;
-+
-+ stc = readl(__io_address(ST_BASE + 0x04));
-+ writel(stc + cycles, __io_address(ST_BASE + 0x18)); /* stc3 */
-+ return 0;
-+}
-+
-+static struct clock_event_device timer0_clockevent = {
-+ .name = "timer0",
-+ .shift = 32,
-+ .features = CLOCK_EVT_FEAT_ONESHOT,
-+ .set_mode = timer_set_mode,
-+ .set_next_event = timer_set_next_event,
-+};
-+
-+/*
-+ * IRQ handler for the timer
-+ */
-+static irqreturn_t bcm2708_timer_interrupt(int irq, void *dev_id)
-+{
-+ struct clock_event_device *evt = &timer0_clockevent;
-+
-+ writel(1 << 3, __io_address(ST_BASE + 0x00)); /* stcs clear timer int */
-+
-+ evt->event_handler(evt);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static struct irqaction bcm2708_timer_irq = {
-+ .name = "BCM2708 Timer Tick",
-+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-+ .handler = bcm2708_timer_interrupt,
-+};
-+
-+/*
-+ * Set up timer interrupt, and return the current time in seconds.
-+ */
-+
-+static struct delay_timer bcm2708_delay_timer = {
-+ .read_current_timer = bcm2708_read_current_timer,
-+ .freq = STC_FREQ_HZ,
-+};
-+
-+static void __init bcm2708_timer_init(void)
-+{
-+ /* init high res timer */
-+ bcm2708_clocksource_init();
-+
-+ /*
-+ * Initialise to a known state (all timers off)
-+ */
-+ writel(0, __io_address(ARM_T_CONTROL));
-+ /*
-+ * Make irqs happen for the system timer
-+ */
-+ setup_irq(IRQ_TIMER3, &bcm2708_timer_irq);
-+
-+ setup_sched_clock(bcm2708_read_sched_clock, 32, STC_FREQ_HZ);
-+
-+ timer0_clockevent.mult =
-+ div_sc(STC_FREQ_HZ, NSEC_PER_SEC, timer0_clockevent.shift);
-+ timer0_clockevent.max_delta_ns =
-+ clockevent_delta2ns(0xffffffff, &timer0_clockevent);
-+ timer0_clockevent.min_delta_ns =
-+ clockevent_delta2ns(0xf, &timer0_clockevent);
-+
-+ timer0_clockevent.cpumask = cpumask_of(0);
-+ clockevents_register_device(&timer0_clockevent);
-+
-+ register_current_timer_delay(&bcm2708_delay_timer);
-+}
-+
-+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-+#include <linux/leds.h>
-+
-+static struct gpio_led bcm2708_leds[] = {
-+ [0] = {
-+ .gpio = 16,
-+ .name = "led0",
-+ .default_trigger = "mmc0",
-+ .active_low = 1,
-+ },
-+};
-+
-+static struct gpio_led_platform_data bcm2708_led_pdata = {
-+ .num_leds = ARRAY_SIZE(bcm2708_leds),
-+ .leds = bcm2708_leds,
-+};
-+
-+static struct platform_device bcm2708_led_device = {
-+ .name = "leds-gpio",
-+ .id = -1,
-+ .dev = {
-+ .platform_data = &bcm2708_led_pdata,
-+ },
-+};
-+
-+static void __init bcm2708_init_led(void)
-+{
-+ platform_device_register(&bcm2708_led_device);
-+}
-+#else
-+static inline void bcm2708_init_led(void)
-+{
-+}
-+#endif
-+
-+void __init bcm2708_init_early(void)
-+{
-+ /*
-+ * Some devices allocate their coherent buffers from atomic
-+ * context. Increase size of atomic coherent pool to make sure such
-+ * the allocations won't fail.
-+ */
-+ init_dma_coherent_pool_size(SZ_4M);
-+}
-+
-+static void __init board_reserve(void)
-+{
-+#if defined(CONFIG_BCM_VC_CMA)
-+ vc_cma_reserve();
-+#endif
-+}
-+
-+MACHINE_START(BCM2708, "BCM2708")
-+ /* Maintainer: Broadcom Europe Ltd. */
-+ .map_io = bcm2708_map_io,
-+ .init_irq = bcm2708_init_irq,
-+ .init_time = bcm2708_timer_init,
-+ .init_machine = bcm2708_init,
-+ .init_early = bcm2708_init_early,
-+ .reserve = board_reserve,
-+ .restart = bcm2708_restart,
-+MACHINE_END
-+
-+module_param(boardrev, uint, 0644);
-+module_param(serial, uint, 0644);
-+module_param(uart_clock, uint, 0644);
-+module_param(reboot_part, uint, 0644);
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/bcm2708_gpio.c linux-3.11.10/arch/arm/mach-bcm2708/bcm2708_gpio.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/bcm2708_gpio.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/bcm2708_gpio.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,339 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/bcm2708_gpio.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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/spinlock.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/io.h>
-+#include <linux/irq.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <mach/gpio.h>
-+#include <linux/gpio.h>
-+#include <linux/platform_device.h>
-+#include <mach/platform.h>
-+
-+#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
-+#define DRIVER_NAME BCM_GPIO_DRIVER_NAME
-+#define BCM_GPIO_USE_IRQ 1
-+
-+#define GPIOFSEL(x) (0x00+(x)*4)
-+#define GPIOSET(x) (0x1c+(x)*4)
-+#define GPIOCLR(x) (0x28+(x)*4)
-+#define GPIOLEV(x) (0x34+(x)*4)
-+#define GPIOEDS(x) (0x40+(x)*4)
-+#define GPIOREN(x) (0x4c+(x)*4)
-+#define GPIOFEN(x) (0x58+(x)*4)
-+#define GPIOHEN(x) (0x64+(x)*4)
-+#define GPIOLEN(x) (0x70+(x)*4)
-+#define GPIOAREN(x) (0x7c+(x)*4)
-+#define GPIOAFEN(x) (0x88+(x)*4)
-+#define GPIOUD(x) (0x94+(x)*4)
-+#define GPIOUDCLK(x) (0x98+(x)*4)
-+
-+enum { GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT,
-+ GPIO_FSEL_ALT5, GPIO_FSEL_ALT_4,
-+ GPIO_FSEL_ALT0, GPIO_FSEL_ALT1,
-+ GPIO_FSEL_ALT2, GPIO_FSEL_ALT3,
-+};
-+
-+ /* Each of the two spinlocks protects a different set of hardware
-+ * regiters and data structurs. This decouples the code of the IRQ from
-+ * the GPIO code. This also makes the case of a GPIO routine call from
-+ * the IRQ code simpler.
-+ */
-+static DEFINE_SPINLOCK(lock); /* GPIO registers */
-+
-+struct bcm2708_gpio {
-+ struct list_head list;
-+ void __iomem *base;
-+ struct gpio_chip gc;
-+ unsigned long rising;
-+ unsigned long falling;
-+};
-+
-+static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset,
-+ int function)
-+{
-+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
-+ unsigned long flags;
-+ unsigned gpiodir;
-+ unsigned gpio_bank = offset / 10;
-+ unsigned gpio_field_offset = (offset - 10 * gpio_bank) * 3;
-+
-+//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set_function %p (%d,%d)\n", gc, offset, function);
-+ if (offset >= ARCH_NR_GPIOS)
-+ return -EINVAL;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ gpiodir = readl(gpio->base + GPIOFSEL(gpio_bank));
-+ gpiodir &= ~(7 << gpio_field_offset);
-+ gpiodir |= function << gpio_field_offset;
-+ writel(gpiodir, gpio->base + GPIOFSEL(gpio_bank));
-+ spin_unlock_irqrestore(&lock, flags);
-+ gpiodir = readl(gpio->base + GPIOFSEL(gpio_bank));
-+
-+ return 0;
-+}
-+
-+static int bcm2708_gpio_dir_in(struct gpio_chip *gc, unsigned offset)
-+{
-+ return bcm2708_set_function(gc, offset, GPIO_FSEL_INPUT);
-+}
-+
-+static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value);
-+static int bcm2708_gpio_dir_out(struct gpio_chip *gc, unsigned offset,
-+ int value)
-+{
-+ int ret;
-+ ret = bcm2708_set_function(gc, offset, GPIO_FSEL_OUTPUT);
-+ if (ret >= 0)
-+ bcm2708_gpio_set(gc, offset, value);
-+ return ret;
-+}
-+
-+static int bcm2708_gpio_get(struct gpio_chip *gc, unsigned offset)
-+{
-+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
-+ unsigned gpio_bank = offset / 32;
-+ unsigned gpio_field_offset = (offset - 32 * gpio_bank);
-+ unsigned lev;
-+
-+ if (offset >= ARCH_NR_GPIOS)
-+ return 0;
-+ lev = readl(gpio->base + GPIOLEV(gpio_bank));
-+//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_get %p (%d)=%d\n", gc, offset, 0x1 & (lev>>gpio_field_offset));
-+ return 0x1 & (lev >> gpio_field_offset);
-+}
-+
-+static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
-+{
-+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
-+ unsigned gpio_bank = offset / 32;
-+ unsigned gpio_field_offset = (offset - 32 * gpio_bank);
-+//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set %p (%d=%d)\n", gc, offset, value);
-+ if (offset >= ARCH_NR_GPIOS)
-+ return;
-+ if (value)
-+ writel(1 << gpio_field_offset, gpio->base + GPIOSET(gpio_bank));
-+ else
-+ writel(1 << gpio_field_offset, gpio->base + GPIOCLR(gpio_bank));
-+}
-+
-+/*************************************************************************************************************************
-+ * bcm2708 GPIO IRQ
-+ */
-+
-+#if BCM_GPIO_USE_IRQ
-+
-+static int bcm2708_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return gpio_to_irq(gpio);
-+}
-+
-+static int bcm2708_gpio_irq_set_type(struct irq_data *d, unsigned type)
-+{
-+ unsigned irq = d->irq;
-+ struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
-+
-+ if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
-+ return -EINVAL;
-+
-+ if (type & IRQ_TYPE_EDGE_RISING) {
-+ gpio->rising |= (1 << irq_to_gpio(irq));
-+ } else {
-+ gpio->rising &= ~(1 << irq_to_gpio(irq));
-+ }
-+
-+ if (type & IRQ_TYPE_EDGE_FALLING) {
-+ gpio->falling |= (1 << irq_to_gpio(irq));
-+ } else {
-+ gpio->falling &= ~(1 << irq_to_gpio(irq));
-+ }
-+ return 0;
-+}
-+
-+static void bcm2708_gpio_irq_mask(struct irq_data *d)
-+{
-+ unsigned irq = d->irq;
-+ struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
-+ unsigned gn = irq_to_gpio(irq);
-+ unsigned gb = gn / 32;
-+ unsigned long rising = readl(gpio->base + GPIOREN(gb));
-+ unsigned long falling = readl(gpio->base + GPIOFEN(gb));
-+
-+ gn = gn % 32;
-+
-+ writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb));
-+ writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb));
-+}
-+
-+static void bcm2708_gpio_irq_unmask(struct irq_data *d)
-+{
-+ unsigned irq = d->irq;
-+ struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
-+ unsigned gn = irq_to_gpio(irq);
-+ unsigned gb = gn / 32;
-+ unsigned long rising = readl(gpio->base + GPIOREN(gb));
-+ unsigned long falling = readl(gpio->base + GPIOFEN(gb));
-+
-+ gn = gn % 32;
-+
-+ writel(1 << gn, gpio->base + GPIOEDS(gb));
-+
-+ if (gpio->rising & (1 << gn)) {
-+ writel(rising | (1 << gn), gpio->base + GPIOREN(gb));
-+ } else {
-+ writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb));
-+ }
-+
-+ if (gpio->falling & (1 << gn)) {
-+ writel(falling | (1 << gn), gpio->base + GPIOFEN(gb));
-+ } else {
-+ writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb));
-+ }
-+}
-+
-+static struct irq_chip bcm2708_irqchip = {
-+ .name = "GPIO",
-+ .irq_enable = bcm2708_gpio_irq_unmask,
-+ .irq_disable = bcm2708_gpio_irq_mask,
-+ .irq_unmask = bcm2708_gpio_irq_unmask,
-+ .irq_mask = bcm2708_gpio_irq_mask,
-+ .irq_set_type = bcm2708_gpio_irq_set_type,
-+};
-+
-+static irqreturn_t bcm2708_gpio_interrupt(int irq, void *dev_id)
-+{
-+ unsigned long edsr;
-+ unsigned bank;
-+ int i;
-+ unsigned gpio;
-+ for (bank = 0; bank <= 1; bank++) {
-+ edsr = readl(__io_address(GPIO_BASE) + GPIOEDS(bank));
-+ for_each_set_bit(i, &edsr, 32) {
-+ gpio = i + bank * 32;
-+ generic_handle_irq(gpio_to_irq(gpio));
-+ }
-+ writel(0xffffffff, __io_address(GPIO_BASE) + GPIOEDS(bank));
-+ }
-+ return IRQ_HANDLED;
-+}
-+
-+static struct irqaction bcm2708_gpio_irq = {
-+ .name = "BCM2708 GPIO catchall handler",
-+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-+ .handler = bcm2708_gpio_interrupt,
-+};
-+
-+static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
-+{
-+ unsigned irq;
-+
-+ ucb->gc.to_irq = bcm2708_gpio_to_irq;
-+
-+ for (irq = GPIO_IRQ_START; irq < (GPIO_IRQ_START + GPIO_IRQS); irq++) {
-+ irq_set_chip_data(irq, ucb);
-+ irq_set_chip(irq, &bcm2708_irqchip);
-+ set_irq_flags(irq, IRQF_VALID);
-+ }
-+ setup_irq(IRQ_GPIO3, &bcm2708_gpio_irq);
-+}
-+
-+#else
-+
-+static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
-+{
-+}
-+
-+#endif /* #if BCM_GPIO_USE_IRQ ***************************************************************************************************************** */
-+
-+static int bcm2708_gpio_probe(struct platform_device *dev)
-+{
-+ struct bcm2708_gpio *ucb;
-+ struct resource *res;
-+ int err = 0;
-+
-+ printk(KERN_INFO DRIVER_NAME ": bcm2708_gpio_probe %p\n", dev);
-+
-+ ucb = kzalloc(sizeof(*ucb), GFP_KERNEL);
-+ if (NULL == ucb) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to allocate "
-+ "mailbox memory\n");
-+ err = -ENOMEM;
-+ goto err;
-+ }
-+
-+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-+
-+ platform_set_drvdata(dev, ucb);
-+ ucb->base = __io_address(GPIO_BASE);
-+
-+ ucb->gc.label = "bcm2708_gpio";
-+ ucb->gc.base = 0;
-+ ucb->gc.ngpio = ARCH_NR_GPIOS;
-+ ucb->gc.owner = THIS_MODULE;
-+
-+ ucb->gc.direction_input = bcm2708_gpio_dir_in;
-+ ucb->gc.direction_output = bcm2708_gpio_dir_out;
-+ ucb->gc.get = bcm2708_gpio_get;
-+ ucb->gc.set = bcm2708_gpio_set;
-+ ucb->gc.can_sleep = 0;
-+
-+ bcm2708_gpio_irq_init(ucb);
-+
-+ err = gpiochip_add(&ucb->gc);
-+ if (err)
-+ goto err;
-+
-+err:
-+ return err;
-+
-+}
-+
-+static int bcm2708_gpio_remove(struct platform_device *dev)
-+{
-+ int err = 0;
-+ struct bcm2708_gpio *ucb = platform_get_drvdata(dev);
-+
-+ printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_remove %p\n", dev);
-+
-+ err = gpiochip_remove(&ucb->gc);
-+
-+ platform_set_drvdata(dev, NULL);
-+ kfree(ucb);
-+
-+ return err;
-+}
-+
-+static struct platform_driver bcm2708_gpio_driver = {
-+ .probe = bcm2708_gpio_probe,
-+ .remove = bcm2708_gpio_remove,
-+ .driver = {
-+ .name = "bcm2708_gpio"},
-+};
-+
-+static int __init bcm2708_gpio_init(void)
-+{
-+ return platform_driver_register(&bcm2708_gpio_driver);
-+}
-+
-+static void __exit bcm2708_gpio_exit(void)
-+{
-+ platform_driver_unregister(&bcm2708_gpio_driver);
-+}
-+
-+module_init(bcm2708_gpio_init);
-+module_exit(bcm2708_gpio_exit);
-+
-+MODULE_DESCRIPTION("Broadcom BCM2708 GPIO driver");
-+MODULE_LICENSE("GPL");
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/bcm2708.h linux-3.11.10/arch/arm/mach-bcm2708/bcm2708.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/bcm2708.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/bcm2708.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,51 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/bcm2708.h
-+ *
-+ * BCM2708 machine support header
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef __BCM2708_BCM2708_H
-+#define __BCM2708_BCM2708_H
-+
-+#include <linux/amba/bus.h>
-+
-+extern void __init bcm2708_init(void);
-+extern void __init bcm2708_init_irq(void);
-+extern void __init bcm2708_map_io(void);
-+extern struct sys_timer bcm2708_timer;
-+extern unsigned int mmc_status(struct device *dev);
-+
-+#define AMBA_DEVICE(name, busid, base, plat) \
-+static struct amba_device name##_device = { \
-+ .dev = { \
-+ .coherent_dma_mask = ~0, \
-+ .init_name = busid, \
-+ .platform_data = plat, \
-+ }, \
-+ .res = { \
-+ .start = base##_BASE, \
-+ .end = (base##_BASE) + SZ_4K - 1,\
-+ .flags = IORESOURCE_MEM, \
-+ }, \
-+ .dma_mask = ~0, \
-+ .irq = base##_IRQ, \
-+ /* .dma = base##_DMA,*/ \
-+}
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/clock.c linux-3.11.10/arch/arm/mach-bcm2708/clock.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/clock.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/clock.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,61 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/clock.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/device.h>
-+#include <linux/list.h>
-+#include <linux/errno.h>
-+#include <linux/err.h>
-+#include <linux/string.h>
-+#include <linux/clk.h>
-+#include <linux/mutex.h>
-+
-+#include <asm/clkdev.h>
-+
-+#include "clock.h"
-+
-+int clk_enable(struct clk *clk)
-+{
-+ return 0;
-+}
-+EXPORT_SYMBOL(clk_enable);
-+
-+void clk_disable(struct clk *clk)
-+{
-+}
-+EXPORT_SYMBOL(clk_disable);
-+
-+unsigned long clk_get_rate(struct clk *clk)
-+{
-+ return clk->rate;
-+}
-+EXPORT_SYMBOL(clk_get_rate);
-+
-+long clk_round_rate(struct clk *clk, unsigned long rate)
-+{
-+ return clk->rate;
-+}
-+EXPORT_SYMBOL(clk_round_rate);
-+
-+int clk_set_rate(struct clk *clk, unsigned long rate)
-+{
-+ return -EIO;
-+}
-+EXPORT_SYMBOL(clk_set_rate);
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/clock.h linux-3.11.10/arch/arm/mach-bcm2708/clock.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/clock.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/clock.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,24 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/clock.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+struct module;
-+
-+struct clk {
-+ unsigned long rate;
-+};
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/dma.c linux-3.11.10/arch/arm/mach-bcm2708/dma.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/dma.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/dma.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,399 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/dma.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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/slab.h>
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/scatterlist.h>
-+
-+#include <mach/dma.h>
-+#include <mach/irqs.h>
-+
-+/*****************************************************************************\
-+ * *
-+ * Configuration *
-+ * *
-+\*****************************************************************************/
-+
-+#define CACHE_LINE_MASK 31
-+#define DRIVER_NAME BCM_DMAMAN_DRIVER_NAME
-+#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */
-+
-+/* valid only for channels 0 - 14, 15 has its own base address */
-+#define BCM2708_DMA_CHAN(n) ((n)<<8) /* base address */
-+#define BCM2708_DMA_CHANIO(dma_base, n) \
-+ ((void __iomem *)((char *)(dma_base)+BCM2708_DMA_CHAN(n)))
-+
-+
-+/*****************************************************************************\
-+ * *
-+ * DMA Auxilliary Functions *
-+ * *
-+\*****************************************************************************/
-+
-+/* A DMA buffer on an arbitrary boundary may separate a cache line into a
-+ section inside the DMA buffer and another section outside it.
-+ Even if we flush DMA buffers from the cache there is always the chance that
-+ during a DMA someone will access the part of a cache line that is outside
-+ the DMA buffer - which will then bring in unwelcome data.
-+ Without being able to dictate our own buffer pools we must insist that
-+ DMA buffers consist of a whole number of cache lines.
-+*/
-+
-+extern int
-+bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len)
-+{
-+ int i;
-+
-+ for (i = 0; i < sg_len; i++) {
-+ if (sg_ptr[i].offset & CACHE_LINE_MASK ||
-+ sg_ptr[i].length & CACHE_LINE_MASK)
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma);
-+
-+extern void
-+bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block)
-+{
-+ dsb(); /* ARM data synchronization (push) operation */
-+
-+ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR);
-+ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS);
-+}
-+
-+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
-+{
-+ dsb();
-+
-+ /* ugly busy wait only option for now */
-+ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE)
-+ cpu_relax();
-+}
-+
-+EXPORT_SYMBOL_GPL(bcm_dma_start);
-+
-+/* Complete an ongoing DMA (assuming its results are to be ignored)
-+ Does nothing if there is no DMA in progress.
-+ This routine waits for the current AXI transfer to complete before
-+ terminating the current DMA. If the current transfer is hung on a DREQ used
-+ by an uncooperative peripheral the AXI transfer may never complete. In this
-+ case the routine times out and return a non-zero error code.
-+ Use of this routine doesn't guarantee that the ongoing or aborted DMA
-+ does not produce an interrupt.
-+*/
-+extern int
-+bcm_dma_abort(void __iomem *dma_chan_base)
-+{
-+ unsigned long int cs;
-+ int rc = 0;
-+
-+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
-+
-+ if (BCM2708_DMA_ACTIVE & cs) {
-+ long int timeout = 10000;
-+
-+ /* write 0 to the active bit - pause the DMA */
-+ writel(0, dma_chan_base + BCM2708_DMA_CS);
-+
-+ /* wait for any current AXI transfer to complete */
-+ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0)
-+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
-+
-+ if (0 != (cs & BCM2708_DMA_ISPAUSED)) {
-+ /* we'll un-pause when we set of our next DMA */
-+ rc = -ETIMEDOUT;
-+
-+ } else if (BCM2708_DMA_ACTIVE & cs) {
-+ /* terminate the control block chain */
-+ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB);
-+
-+ /* abort the whole DMA */
-+ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE,
-+ dma_chan_base + BCM2708_DMA_CS);
-+ }
-+ }
-+
-+ return rc;
-+}
-+EXPORT_SYMBOL_GPL(bcm_dma_abort);
-+
-+
-+/***************************************************************************** \
-+ * *
-+ * DMA Manager Device Methods *
-+ * *
-+\*****************************************************************************/
-+
-+struct vc_dmaman {
-+ void __iomem *dma_base;
-+ u32 chan_available; /* bitmap of available channels */
-+ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */
-+};
-+
-+static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base,
-+ u32 chans_available)
-+{
-+ dmaman->dma_base = dma_base;
-+ dmaman->chan_available = chans_available;
-+ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* chans 2 & 3 */
-+ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* chan 0 */
-+}
-+
-+static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
-+ unsigned preferred_feature_set)
-+{
-+ u32 chans;
-+ int feature;
-+
-+ chans = dmaman->chan_available;
-+ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++)
-+ /* select the subset of available channels with the desired
-+ feature so long as some of the candidate channels have that
-+ feature */
-+ if ((preferred_feature_set & (1 << feature)) &&
-+ (chans & dmaman->has_feature[feature]))
-+ chans &= dmaman->has_feature[feature];
-+
-+ if (chans) {
-+ int chan = 0;
-+ /* return the ordinal of the first channel in the bitmap */
-+ while (chans != 0 && (chans & 1) == 0) {
-+ chans >>= 1;
-+ chan++;
-+ }
-+ /* claim the channel */
-+ dmaman->chan_available &= ~(1 << chan);
-+ return chan;
-+ } else
-+ return -ENOMEM;
-+}
-+
-+static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan)
-+{
-+ if (chan < 0)
-+ return -EINVAL;
-+ else if ((1 << chan) & dmaman->chan_available)
-+ return -EIDRM;
-+ else {
-+ dmaman->chan_available |= (1 << chan);
-+ return 0;
-+ }
-+}
-+
-+/*****************************************************************************\
-+ * *
-+ * DMA IRQs *
-+ * *
-+\*****************************************************************************/
-+
-+static unsigned char bcm_dma_irqs[] = {
-+ IRQ_DMA0,
-+ IRQ_DMA1,
-+ IRQ_DMA2,
-+ IRQ_DMA3,
-+ IRQ_DMA4,
-+ IRQ_DMA5,
-+ IRQ_DMA6,
-+ IRQ_DMA7,
-+ IRQ_DMA8,
-+ IRQ_DMA9,
-+ IRQ_DMA10,
-+ IRQ_DMA11,
-+ IRQ_DMA12
-+};
-+
-+
-+/***************************************************************************** \
-+ * *
-+ * DMA Manager Monitor *
-+ * *
-+\*****************************************************************************/
-+
-+static struct device *dmaman_dev; /* we assume there's only one! */
-+
-+extern int bcm_dma_chan_alloc(unsigned preferred_feature_set,
-+ void __iomem **out_dma_base, int *out_dma_irq)
-+{
-+ if (!dmaman_dev)
-+ return -ENODEV;
-+ else {
-+ struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev);
-+ int rc;
-+
-+ device_lock(dmaman_dev);
-+ rc = vc_dmaman_chan_alloc(dmaman, preferred_feature_set);
-+ if (rc >= 0) {
-+ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base,
-+ rc);
-+ *out_dma_irq = bcm_dma_irqs[rc];
-+ }
-+ device_unlock(dmaman_dev);
-+
-+ return rc;
-+ }
-+}
-+EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc);
-+
-+extern int bcm_dma_chan_free(int channel)
-+{
-+ if (dmaman_dev) {
-+ struct vc_dmaman *dmaman = dev_get_drvdata(dmaman_dev);
-+ int rc;
-+
-+ device_lock(dmaman_dev);
-+ rc = vc_dmaman_chan_free(dmaman, channel);
-+ device_unlock(dmaman_dev);
-+
-+ return rc;
-+ } else
-+ return -ENODEV;
-+}
-+EXPORT_SYMBOL_GPL(bcm_dma_chan_free);
-+
-+static int dev_dmaman_register(const char *dev_name, struct device *dev)
-+{
-+ int rc = dmaman_dev ? -EINVAL : 0;
-+ dmaman_dev = dev;
-+ return rc;
-+}
-+
-+static void dev_dmaman_deregister(const char *dev_name, struct device *dev)
-+{
-+ dmaman_dev = NULL;
-+}
-+
-+/*****************************************************************************\
-+ * *
-+ * DMA Device *
-+ * *
-+\*****************************************************************************/
-+
-+static int dmachans = -1; /* module parameter */
-+
-+static int bcm_dmaman_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+ struct vc_dmaman *dmaman;
-+ struct resource *dma_res = NULL;
-+ void __iomem *dma_base = NULL;
-+ int have_dma_region = 0;
-+
-+ dmaman = kzalloc(sizeof(*dmaman), GFP_KERNEL);
-+ if (NULL == dmaman) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to allocate "
-+ "DMA management memory\n");
-+ ret = -ENOMEM;
-+ } else {
-+
-+ dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (dma_res == NULL) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to obtain memory "
-+ "resource\n");
-+ ret = -ENODEV;
-+ } else if (!request_mem_region(dma_res->start,
-+ resource_size(dma_res),
-+ DRIVER_NAME)) {
-+ dev_err(&pdev->dev, "cannot obtain DMA region\n");
-+ ret = -EBUSY;
-+ } else {
-+ have_dma_region = 1;
-+ dma_base = ioremap(dma_res->start,
-+ resource_size(dma_res));
-+ if (!dma_base) {
-+ dev_err(&pdev->dev, "cannot map DMA region\n");
-+ ret = -ENOMEM;
-+ } else {
-+ /* use module parameter if one was provided */
-+ if (dmachans > 0)
-+ vc_dmaman_init(dmaman, dma_base,
-+ dmachans);
-+ else
-+ vc_dmaman_init(dmaman, dma_base,
-+ DEFAULT_DMACHAN_BITMAP);
-+
-+ platform_set_drvdata(pdev, dmaman);
-+ dev_dmaman_register(DRIVER_NAME, &pdev->dev);
-+
-+ printk(KERN_INFO DRIVER_NAME ": DMA manager "
-+ "at %p\n", dma_base);
-+ }
-+ }
-+ }
-+ if (ret != 0) {
-+ if (dma_base)
-+ iounmap(dma_base);
-+ if (dma_res && have_dma_region)
-+ release_mem_region(dma_res->start,
-+ resource_size(dma_res));
-+ if (dmaman)
-+ kfree(dmaman);
-+ }
-+ return ret;
-+}
-+
-+static int bcm_dmaman_remove(struct platform_device *pdev)
-+{
-+ struct vc_dmaman *dmaman = platform_get_drvdata(pdev);
-+
-+ platform_set_drvdata(pdev, NULL);
-+ dev_dmaman_deregister(DRIVER_NAME, &pdev->dev);
-+ kfree(dmaman);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm_dmaman_driver = {
-+ .probe = bcm_dmaman_probe,
-+ .remove = bcm_dmaman_remove,
-+
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+/*****************************************************************************\
-+ * *
-+ * Driver init/exit *
-+ * *
-+\*****************************************************************************/
-+
-+static int __init bcm_dmaman_drv_init(void)
-+{
-+ int ret;
-+
-+ ret = platform_driver_register(&bcm_dmaman_driver);
-+ if (ret != 0) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to register "
-+ "on platform\n");
-+ }
-+
-+ return ret;
-+}
-+
-+static void __exit bcm_dmaman_drv_exit(void)
-+{
-+ platform_driver_unregister(&bcm_dmaman_driver);
-+}
-+
-+module_init(bcm_dmaman_drv_init);
-+module_exit(bcm_dmaman_drv_exit);
-+
-+module_param(dmachans, int, 0644);
-+
-+MODULE_AUTHOR("Gray Girling <grayg@broadcom.com>");
-+MODULE_DESCRIPTION("DMA channel manager driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM");
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/dmaer.c linux-3.11.10/arch/arm/mach-bcm2708/dmaer.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/dmaer.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/dmaer.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,886 @@
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kdev_t.h>
-+#include <linux/fs.h>
-+#include <linux/cdev.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
-+#include <linux/device.h>
-+#include <linux/jiffies.h>
-+#include <linux/timex.h>
-+#include <linux/dma-mapping.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/atomic.h>
-+#include <asm/cacheflush.h>
-+#include <asm/io.h>
-+
-+#include <mach/dma.h>
-+#include <mach/vc_support.h>
-+
-+#ifdef ECLIPSE_IGNORE
-+
-+#define __user
-+#define __init
-+#define __exit
-+#define __iomem
-+#define KERN_DEBUG
-+#define KERN_ERR
-+#define KERN_WARNING
-+#define KERN_INFO
-+#define _IOWR(a, b, c) b
-+#define _IOW(a, b, c) b
-+#define _IO(a, b) b
-+
-+#endif
-+
-+//#define inline
-+
-+#define PRINTK(args...) printk(args)
-+//#define PRINTK_VERBOSE(args...) printk(args)
-+//#define PRINTK(args...)
-+#define PRINTK_VERBOSE(args...)
-+
-+/***** TYPES ****/
-+#define PAGES_PER_LIST 500
-+struct PageList
-+{
-+ struct page *m_pPages[PAGES_PER_LIST];
-+ unsigned int m_used;
-+ struct PageList *m_pNext;
-+};
-+
-+struct VmaPageList
-+{
-+ //each vma has a linked list of pages associated with it
-+ struct PageList *m_pPageHead;
-+ struct PageList *m_pPageTail;
-+ unsigned int m_refCount;
-+};
-+
-+struct DmaControlBlock
-+{
-+ unsigned int m_transferInfo;
-+ void __user *m_pSourceAddr;
-+ void __user *m_pDestAddr;
-+ unsigned int m_xferLen;
-+ unsigned int m_tdStride;
-+ struct DmaControlBlock *m_pNext;
-+ unsigned int m_blank1, m_blank2;
-+};
-+
-+/***** DEFINES ******/
-+//magic number defining the module
-+#define DMA_MAGIC 0xdd
-+
-+//do user virtual to physical translation of the CB chain
-+#define DMA_PREPARE _IOWR(DMA_MAGIC, 0, struct DmaControlBlock *)
-+
-+//kick the pre-prepared CB chain
-+#define DMA_KICK _IOW(DMA_MAGIC, 1, struct DmaControlBlock *)
-+
-+//prepare it, kick it, wait for it
-+#define DMA_PREPARE_KICK_WAIT _IOWR(DMA_MAGIC, 2, struct DmaControlBlock *)
-+
-+//prepare it, kick it, don't wait for it
-+#define DMA_PREPARE_KICK _IOWR(DMA_MAGIC, 3, struct DmaControlBlock *)
-+
-+//not currently implemented
-+#define DMA_WAIT_ONE _IO(DMA_MAGIC, 4, struct DmaControlBlock *)
-+
-+//wait on all kicked CB chains
-+#define DMA_WAIT_ALL _IO(DMA_MAGIC, 5)
-+
-+//in order to discover the largest AXI burst that should be programmed into the transfer params
-+#define DMA_MAX_BURST _IO(DMA_MAGIC, 6)
-+
-+//set the address range through which the user address is assumed to already by a physical address
-+#define DMA_SET_MIN_PHYS _IOW(DMA_MAGIC, 7, unsigned long)
-+#define DMA_SET_MAX_PHYS _IOW(DMA_MAGIC, 8, unsigned long)
-+#define DMA_SET_PHYS_OFFSET _IOW(DMA_MAGIC, 9, unsigned long)
-+
-+//used to define the size for the CMA-based allocation *in pages*, can only be done once once the file is opened
-+#define DMA_CMA_SET_SIZE _IOW(DMA_MAGIC, 10, unsigned long)
-+
-+//used to get the version of the module, to test for a capability
-+#define DMA_GET_VERSION _IO(DMA_MAGIC, 99)
-+
-+#define VERSION_NUMBER 1
-+
-+#define VIRT_TO_BUS_CACHE_SIZE 8
-+
-+/***** FILE OPS *****/
-+static int Open(struct inode *pInode, struct file *pFile);
-+static int Release(struct inode *pInode, struct file *pFile);
-+static long Ioctl(struct file *pFile, unsigned int cmd, unsigned long arg);
-+static ssize_t Read(struct file *pFile, char __user *pUser, size_t count, loff_t *offp);
-+static int Mmap(struct file *pFile, struct vm_area_struct *pVma);
-+
-+/***** VMA OPS ****/
-+static void VmaOpen4k(struct vm_area_struct *pVma);
-+static void VmaClose4k(struct vm_area_struct *pVma);
-+static int VmaFault4k(struct vm_area_struct *pVma, struct vm_fault *pVmf);
-+
-+/**** DMA PROTOTYPES */
-+static struct DmaControlBlock __user *DmaPrepare(struct DmaControlBlock __user *pUserCB, int *pError);
-+static int DmaKick(struct DmaControlBlock __user *pUserCB);
-+static void DmaWaitAll(void);
-+
-+/**** GENERIC ****/
-+static int __init dmaer_init(void);
-+static void __exit dmaer_exit(void);
-+
-+/*** OPS ***/
-+static struct vm_operations_struct g_vmOps4k = {
-+ .open = VmaOpen4k,
-+ .close = VmaClose4k,
-+ .fault = VmaFault4k,
-+};
-+
-+static struct file_operations g_fOps = {
-+ .owner = THIS_MODULE,
-+ .llseek = 0,
-+ .read = Read,
-+ .write = 0,
-+ .unlocked_ioctl = Ioctl,
-+ .open = Open,
-+ .release = Release,
-+ .mmap = Mmap,
-+};
-+
-+/***** GLOBALS ******/
-+static dev_t g_majorMinor;
-+
-+//tracking usage of the two files
-+static atomic_t g_oneLock4k = ATOMIC_INIT(1);
-+
-+//device operations
-+static struct cdev g_cDev;
-+static int g_trackedPages = 0;
-+
-+//dma control
-+static unsigned int *g_pDmaChanBase;
-+static int g_dmaIrq;
-+static int g_dmaChan;
-+
-+//cma allocation
-+static int g_cmaHandle;
-+
-+//user virtual to bus address translation acceleration
-+static unsigned long g_virtAddr[VIRT_TO_BUS_CACHE_SIZE];
-+static unsigned long g_busAddr[VIRT_TO_BUS_CACHE_SIZE];
-+static unsigned long g_cbVirtAddr;
-+static unsigned long g_cbBusAddr;
-+static int g_cacheInsertAt;
-+static int g_cacheHit, g_cacheMiss;
-+
-+//off by default
-+static void __user *g_pMinPhys;
-+static void __user *g_pMaxPhys;
-+static unsigned long g_physOffset;
-+
-+/****** CACHE OPERATIONS ********/
-+static inline void FlushAddrCache(void)
-+{
-+ int count = 0;
-+ for (count = 0; count < VIRT_TO_BUS_CACHE_SIZE; count++)
-+ g_virtAddr[count] = 0xffffffff; //never going to match as we always chop the bottom bits anyway
-+
-+ g_cbVirtAddr = 0xffffffff;
-+
-+ g_cacheInsertAt = 0;
-+}
-+
-+//translate from a user virtual address to a bus address by mapping the page
-+//NB this won't lock a page in memory, so to avoid potential paging issues using kernel logical addresses
-+static inline void __iomem *UserVirtualToBus(void __user *pUser)
-+{
-+ int mapped;
-+ struct page *pPage;
-+ void *phys;
-+
-+ //map it (requiring that the pointer points to something that does not hang off the page boundary)
-+ mapped = get_user_pages(current, current->mm,
-+ (unsigned long)pUser, 1,
-+ 1, 0,
-+ &pPage,
-+ 0);
-+
-+ if (mapped <= 0) //error
-+ return 0;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "user virtual %p arm phys %p bus %p\n",
-+ pUser, page_address(pPage), (void __iomem *)__virt_to_bus(page_address(pPage)));
-+
-+ //get the arm physical address
-+ phys = page_address(pPage) + offset_in_page(pUser);
-+ page_cache_release(pPage);
-+
-+ //and now the bus address
-+ return (void __iomem *)__virt_to_bus(phys);
-+}
-+
-+static inline void __iomem *UserVirtualToBusViaCbCache(void __user *pUser)
-+{
-+ unsigned long virtual_page = (unsigned long)pUser & ~4095;
-+ unsigned long page_offset = (unsigned long)pUser & 4095;
-+ unsigned long bus_addr;
-+
-+ if (g_cbVirtAddr == virtual_page)
-+ {
-+ bus_addr = g_cbBusAddr + page_offset;
-+ g_cacheHit++;
-+ return (void __iomem *)bus_addr;
-+ }
-+ else
-+ {
-+ bus_addr = (unsigned long)UserVirtualToBus(pUser);
-+
-+ if (!bus_addr)
-+ return 0;
-+
-+ g_cbVirtAddr = virtual_page;
-+ g_cbBusAddr = bus_addr & ~4095;
-+ g_cacheMiss++;
-+
-+ return (void __iomem *)bus_addr;
-+ }
-+}
-+
-+//do the same as above, by query our virt->bus cache
-+static inline void __iomem *UserVirtualToBusViaCache(void __user *pUser)
-+{
-+ int count;
-+ //get the page and its offset
-+ unsigned long virtual_page = (unsigned long)pUser & ~4095;
-+ unsigned long page_offset = (unsigned long)pUser & 4095;
-+ unsigned long bus_addr;
-+
-+ if (pUser >= g_pMinPhys && pUser < g_pMaxPhys)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "user->phys passthrough on %p\n", pUser);
-+ return (void __iomem *)((unsigned long)pUser + g_physOffset);
-+ }
-+
-+ //check the cache for our entry
-+ for (count = 0; count < VIRT_TO_BUS_CACHE_SIZE; count++)
-+ if (g_virtAddr[count] == virtual_page)
-+ {
-+ bus_addr = g_busAddr[count] + page_offset;
-+ g_cacheHit++;
-+ return (void __iomem *)bus_addr;
-+ }
-+
-+ //not found, look up manually and then insert its page address
-+ bus_addr = (unsigned long)UserVirtualToBus(pUser);
-+
-+ if (!bus_addr)
-+ return 0;
-+
-+ g_virtAddr[g_cacheInsertAt] = virtual_page;
-+ g_busAddr[g_cacheInsertAt] = bus_addr & ~4095;
-+
-+ //round robin
-+ g_cacheInsertAt++;
-+ if (g_cacheInsertAt == VIRT_TO_BUS_CACHE_SIZE)
-+ g_cacheInsertAt = 0;
-+
-+ g_cacheMiss++;
-+
-+ return (void __iomem *)bus_addr;
-+}
-+
-+/***** FILE OPERATIONS ****/
-+static int Open(struct inode *pInode, struct file *pFile)
-+{
-+ PRINTK(KERN_DEBUG "file opening: %d/%d\n", imajor(pInode), iminor(pInode));
-+
-+ //check which device we are
-+ if (iminor(pInode) == 0) //4k
-+ {
-+ //only one at a time
-+ if (!atomic_dec_and_test(&g_oneLock4k))
-+ {
-+ atomic_inc(&g_oneLock4k);
-+ return -EBUSY;
-+ }
-+ }
-+ else
-+ return -EINVAL;
-+
-+ //todo there will be trouble if two different processes open the files
-+
-+ //reset after any file is opened
-+ g_pMinPhys = (void __user *)-1;
-+ g_pMaxPhys = (void __user *)0;
-+ g_physOffset = 0;
-+ g_cmaHandle = 0;
-+
-+ return 0;
-+}
-+
-+static int Release(struct inode *pInode, struct file *pFile)
-+{
-+ PRINTK(KERN_DEBUG "file closing, %d pages tracked\n", g_trackedPages);
-+ if (g_trackedPages)
-+ PRINTK(KERN_ERR "we\'re leaking memory!\n");
-+
-+ //wait for any dmas to finish
-+ DmaWaitAll();
-+
-+ //free this memory on the application closing the file or it crashing (implicitly closing the file)
-+ if (g_cmaHandle)
-+ {
-+ PRINTK(KERN_DEBUG "unlocking vc memory\n");
-+ if (UnlockVcMemory(g_cmaHandle))
-+ PRINTK(KERN_ERR "uh-oh, unable to unlock vc memory!\n");
-+ PRINTK(KERN_DEBUG "releasing vc memory\n");
-+ if (ReleaseVcMemory(g_cmaHandle))
-+ PRINTK(KERN_ERR "uh-oh, unable to release vc memory!\n");
-+ }
-+
-+ if (iminor(pInode) == 0)
-+ atomic_inc(&g_oneLock4k);
-+ else
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static struct DmaControlBlock __user *DmaPrepare(struct DmaControlBlock __user *pUserCB, int *pError)
-+{
-+ struct DmaControlBlock kernCB;
-+ struct DmaControlBlock __user *pUNext;
-+ void __iomem *pSourceBus, __iomem *pDestBus;
-+
-+ //get the control block into kernel memory so we can work on it
-+ if (copy_from_user(&kernCB, pUserCB, sizeof(struct DmaControlBlock)) != 0)
-+ {
-+ PRINTK(KERN_ERR "copy_from_user failed for user cb %p\n", pUserCB);
-+ *pError = 1;
-+ return 0;
-+ }
-+
-+ if (kernCB.m_pSourceAddr == 0 || kernCB.m_pDestAddr == 0)
-+ {
-+ PRINTK(KERN_ERR "faulty source (%p) dest (%p) addresses for user cb %p\n",
-+ kernCB.m_pSourceAddr, kernCB.m_pDestAddr, pUserCB);
-+ *pError = 1;
-+ return 0;
-+ }
-+
-+ pSourceBus = UserVirtualToBusViaCache(kernCB.m_pSourceAddr);
-+ pDestBus = UserVirtualToBusViaCache(kernCB.m_pDestAddr);
-+
-+ if (!pSourceBus || !pDestBus)
-+ {
-+ PRINTK(KERN_ERR "virtual to bus translation failure for source/dest %p/%p->%p/%p\n",
-+ kernCB.m_pSourceAddr, kernCB.m_pDestAddr,
-+ pSourceBus, pDestBus);
-+ *pError = 1;
-+ return 0;
-+ }
-+
-+ //update the user structure with the new bus addresses
-+ kernCB.m_pSourceAddr = pSourceBus;
-+ kernCB.m_pDestAddr = pDestBus;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "final source %p dest %p\n", kernCB.m_pSourceAddr, kernCB.m_pDestAddr);
-+
-+ //sort out the bus address for the next block
-+ pUNext = kernCB.m_pNext;
-+
-+ if (kernCB.m_pNext)
-+ {
-+ void __iomem *pNextBus;
-+ pNextBus = UserVirtualToBusViaCbCache(kernCB.m_pNext);
-+
-+ if (!pNextBus)
-+ {
-+ PRINTK(KERN_ERR "virtual to bus translation failure for m_pNext\n");
-+ *pError = 1;
-+ return 0;
-+ }
-+
-+ //update the pointer with the bus address
-+ kernCB.m_pNext = pNextBus;
-+ }
-+
-+ //write it back to user space
-+ if (copy_to_user(pUserCB, &kernCB, sizeof(struct DmaControlBlock)) != 0)
-+ {
-+ PRINTK(KERN_ERR "copy_to_user failed for cb %p\n", pUserCB);
-+ *pError = 1;
-+ return 0;
-+ }
-+
-+ __cpuc_flush_dcache_area(pUserCB, 32);
-+
-+ *pError = 0;
-+ return pUNext;
-+}
-+
-+static int DmaKick(struct DmaControlBlock __user *pUserCB)
-+{
-+ void __iomem *pBusCB;
-+
-+ pBusCB = UserVirtualToBusViaCbCache(pUserCB);
-+ if (!pBusCB)
-+ {
-+ PRINTK(KERN_ERR "virtual to bus translation failure for cb\n");
-+ return 1;
-+ }
-+
-+ //flush_cache_all();
-+
-+ bcm_dma_start(g_pDmaChanBase, (dma_addr_t)pBusCB);
-+
-+ return 0;
-+}
-+
-+static void DmaWaitAll(void)
-+{
-+ int counter = 0;
-+ volatile int inner_count;
-+ volatile unsigned int cs;
-+ unsigned long time_before, time_after;
-+
-+ time_before = jiffies;
-+ //bcm_dma_wait_idle(g_pDmaChanBase);
-+ dsb();
-+
-+ cs = readl(g_pDmaChanBase);
-+
-+ while ((cs & 1) == 1)
-+ {
-+ cs = readl(g_pDmaChanBase);
-+ counter++;
-+
-+ for (inner_count = 0; inner_count < 32; inner_count++);
-+
-+ asm volatile ("MCR p15,0,r0,c7,c0,4 \n");
-+ //cpu_do_idle();
-+ if (counter >= 1000000)
-+ {
-+ PRINTK(KERN_WARNING "DMA failed to finish in a timely fashion\n");
-+ break;
-+ }
-+ }
-+ time_after = jiffies;
-+ PRINTK_VERBOSE(KERN_DEBUG "done, counter %d, cs %08x", counter, cs);
-+ PRINTK_VERBOSE(KERN_DEBUG "took %ld jiffies, %d HZ\n", time_after - time_before, HZ);
-+}
-+
-+static long Ioctl(struct file *pFile, unsigned int cmd, unsigned long arg)
-+{
-+ int error = 0;
-+ PRINTK_VERBOSE(KERN_DEBUG "ioctl cmd %x arg %lx\n", cmd, arg);
-+
-+ switch (cmd)
-+ {
-+ case DMA_PREPARE:
-+ case DMA_PREPARE_KICK:
-+ case DMA_PREPARE_KICK_WAIT:
-+ {
-+ struct DmaControlBlock __user *pUCB = (struct DmaControlBlock *)arg;
-+ int steps = 0;
-+ unsigned long start_time = jiffies;
-+ (void)start_time;
-+
-+ //flush our address cache
-+ FlushAddrCache();
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "dma prepare\n");
-+
-+ //do virtual to bus translation for each entry
-+ do
-+ {
-+ pUCB = DmaPrepare(pUCB, &error);
-+ } while (error == 0 && ++steps && pUCB);
-+ PRINTK_VERBOSE(KERN_DEBUG "prepare done in %d steps, %ld\n", steps, jiffies - start_time);
-+
-+ //carry straight on if we want to kick too
-+ if (cmd == DMA_PREPARE || error)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "falling out\n");
-+ return error ? -EINVAL : 0;
-+ }
-+ }
-+ case DMA_KICK:
-+ PRINTK_VERBOSE(KERN_DEBUG "dma begin\n");
-+
-+ if (cmd == DMA_KICK)
-+ FlushAddrCache();
-+
-+ DmaKick((struct DmaControlBlock __user *)arg);
-+
-+ if (cmd != DMA_PREPARE_KICK_WAIT)
-+ break;
-+/* case DMA_WAIT_ONE:
-+ //PRINTK(KERN_DEBUG "dma wait one\n");
-+ break;*/
-+ case DMA_WAIT_ALL:
-+ //PRINTK(KERN_DEBUG "dma wait all\n");
-+ DmaWaitAll();
-+ break;
-+ case DMA_MAX_BURST:
-+ if (g_dmaChan == 0)
-+ return 10;
-+ else
-+ return 5;
-+ case DMA_SET_MIN_PHYS:
-+ g_pMinPhys = (void __user *)arg;
-+ PRINTK(KERN_DEBUG "min/max user/phys bypass set to %p %p\n", g_pMinPhys, g_pMaxPhys);
-+ break;
-+ case DMA_SET_MAX_PHYS:
-+ g_pMaxPhys = (void __user *)arg;
-+ PRINTK(KERN_DEBUG "min/max user/phys bypass set to %p %p\n", g_pMinPhys, g_pMaxPhys);
-+ break;
-+ case DMA_SET_PHYS_OFFSET:
-+ g_physOffset = arg;
-+ PRINTK(KERN_DEBUG "user/phys bypass offset set to %ld\n", g_physOffset);
-+ break;
-+ case DMA_CMA_SET_SIZE:
-+ {
-+ unsigned int pBusAddr;
-+
-+ if (g_cmaHandle)
-+ {
-+ PRINTK(KERN_ERR "memory has already been allocated (handle %d)\n", g_cmaHandle);
-+ return -EINVAL;
-+ }
-+
-+ PRINTK(KERN_INFO "allocating %ld bytes of VC memory\n", arg * 4096);
-+
-+ //get the memory
-+ if (AllocateVcMemory(&g_cmaHandle, arg * 4096, 4096, MEM_FLAG_L1_NONALLOCATING | MEM_FLAG_NO_INIT | MEM_FLAG_HINT_PERMALOCK))
-+ {
-+ PRINTK(KERN_ERR "failed to allocate %ld bytes of VC memory\n", arg * 4096);
-+ g_cmaHandle = 0;
-+ return -EINVAL;
-+ }
-+
-+ //get an address for it
-+ PRINTK(KERN_INFO "trying to map VC memory\n");
-+
-+ if (LockVcMemory(&pBusAddr, g_cmaHandle))
-+ {
-+ PRINTK(KERN_ERR "failed to map CMA handle %d, releasing memory\n", g_cmaHandle);
-+ ReleaseVcMemory(g_cmaHandle);
-+ g_cmaHandle = 0;
-+ }
-+
-+ PRINTK(KERN_INFO "bus address for CMA memory is %x\n", pBusAddr);
-+ return pBusAddr;
-+ }
-+ case DMA_GET_VERSION:
-+ PRINTK(KERN_DEBUG "returning version number, %d\n", VERSION_NUMBER);
-+ return VERSION_NUMBER;
-+ default:
-+ PRINTK(KERN_DEBUG "unknown ioctl: %d\n", cmd);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static ssize_t Read(struct file *pFile, char __user *pUser, size_t count, loff_t *offp)
-+{
-+ return -EIO;
-+}
-+
-+static int Mmap(struct file *pFile, struct vm_area_struct *pVma)
-+{
-+ struct PageList *pPages;
-+ struct VmaPageList *pVmaList;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "MMAP vma %p, length %ld (%s %d)\n",
-+ pVma, pVma->vm_end - pVma->vm_start,
-+ current->comm, current->pid);
-+ PRINTK_VERBOSE(KERN_DEBUG "MMAP %p %d (tracked %d)\n", pVma, current->pid, g_trackedPages);
-+
-+ //make a new page list
-+ pPages = (struct PageList *)kmalloc(sizeof(struct PageList), GFP_KERNEL);
-+ if (!pPages)
-+ {
-+ PRINTK(KERN_ERR "couldn\'t allocate a new page list (%s %d)\n",
-+ current->comm, current->pid);
-+ return -ENOMEM;
-+ }
-+
-+ //clear the page list
-+ pPages->m_used = 0;
-+ pPages->m_pNext = 0;
-+
-+ //insert our vma and new page list somewhere
-+ if (!pVma->vm_private_data)
-+ {
-+ struct VmaPageList *pList;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "new vma list, making new one (%s %d)\n",
-+ current->comm, current->pid);
-+
-+ //make a new vma list
-+ pList = (struct VmaPageList *)kmalloc(sizeof(struct VmaPageList), GFP_KERNEL);
-+ if (!pList)
-+ {
-+ PRINTK(KERN_ERR "couldn\'t allocate vma page list (%s %d)\n",
-+ current->comm, current->pid);
-+ kfree(pPages);
-+ return -ENOMEM;
-+ }
-+
-+ //clear this list
-+ pVma->vm_private_data = (void *)pList;
-+ pList->m_refCount = 0;
-+ }
-+
-+ pVmaList = (struct VmaPageList *)pVma->vm_private_data;
-+
-+ //add it to the vma list
-+ pVmaList->m_pPageHead = pPages;
-+ pVmaList->m_pPageTail = pPages;
-+
-+ pVma->vm_ops = &g_vmOps4k;
-+ pVma->vm_flags |= VM_IO;
-+
-+ VmaOpen4k(pVma);
-+
-+ return 0;
-+}
-+
-+/****** VMA OPERATIONS ******/
-+
-+static void VmaOpen4k(struct vm_area_struct *pVma)
-+{
-+ struct VmaPageList *pVmaList;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "vma open %p private %p (%s %d), %d live pages\n", pVma, pVma->vm_private_data, current->comm, current->pid, g_trackedPages);
-+ PRINTK_VERBOSE(KERN_DEBUG "OPEN %p %d %ld pages (tracked pages %d)\n",
-+ pVma, current->pid, (pVma->vm_end - pVma->vm_start) >> 12,
-+ g_trackedPages);
-+
-+ pVmaList = (struct VmaPageList *)pVma->vm_private_data;
-+
-+ if (pVmaList)
-+ {
-+ pVmaList->m_refCount++;
-+ PRINTK_VERBOSE(KERN_DEBUG "ref count is now %d\n", pVmaList->m_refCount);
-+ }
-+ else
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "err, open but no vma page list\n");
-+ }
-+}
-+
-+static void VmaClose4k(struct vm_area_struct *pVma)
-+{
-+ struct VmaPageList *pVmaList;
-+ int freed = 0;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "vma close %p private %p (%s %d)\n", pVma, pVma->vm_private_data, current->comm, current->pid);
-+
-+ //wait for any dmas to finish
-+ DmaWaitAll();
-+
-+ //find our vma in the list
-+ pVmaList = (struct VmaPageList *)pVma->vm_private_data;
-+
-+ //may be a fork
-+ if (pVmaList)
-+ {
-+ struct PageList *pPages;
-+
-+ pVmaList->m_refCount--;
-+
-+ if (pVmaList->m_refCount == 0)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "found vma, freeing pages (%s %d)\n",
-+ current->comm, current->pid);
-+
-+ pPages = pVmaList->m_pPageHead;
-+
-+ if (!pPages)
-+ {
-+ PRINTK(KERN_ERR "no page list (%s %d)!\n",
-+ current->comm, current->pid);
-+ return;
-+ }
-+
-+ while (pPages)
-+ {
-+ struct PageList *next;
-+ int count;
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "page list (%s %d)\n",
-+ current->comm, current->pid);
-+
-+ next = pPages->m_pNext;
-+ for (count = 0; count < pPages->m_used; count++)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "freeing page %p (%s %d)\n",
-+ pPages->m_pPages[count],
-+ current->comm, current->pid);
-+ __free_pages(pPages->m_pPages[count], 0);
-+ g_trackedPages--;
-+ freed++;
-+ }
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "freeing page list (%s %d)\n",
-+ current->comm, current->pid);
-+ kfree(pPages);
-+ pPages = next;
-+ }
-+
-+ //remove our vma from the list
-+ kfree(pVmaList);
-+ pVma->vm_private_data = 0;
-+ }
-+ else
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "ref count is %d, not closing\n", pVmaList->m_refCount);
-+ }
-+ }
-+ else
-+ {
-+ PRINTK_VERBOSE(KERN_ERR "uh-oh, vma %p not found (%s %d)!\n", pVma, current->comm, current->pid);
-+ PRINTK_VERBOSE(KERN_ERR "CLOSE ERR\n");
-+ }
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "CLOSE %p %d %d pages (tracked pages %d)",
-+ pVma, current->pid, freed, g_trackedPages);
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "%d pages open\n", g_trackedPages);
-+}
-+
-+static int VmaFault4k(struct vm_area_struct *pVma, struct vm_fault *pVmf)
-+{
-+ PRINTK_VERBOSE(KERN_DEBUG "vma fault for vma %p private %p at offset %ld (%s %d)\n", pVma, pVma->vm_private_data, pVmf->pgoff,
-+ current->comm, current->pid);
-+ PRINTK_VERBOSE(KERN_DEBUG "FAULT\n");
-+ pVmf->page = alloc_page(GFP_KERNEL);
-+
-+ if (pVmf->page)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "alloc page virtual %p\n", page_address(pVmf->page));
-+ }
-+
-+ if (!pVmf->page)
-+ {
-+ PRINTK(KERN_ERR "vma fault oom (%s %d)\n", current->comm, current->pid);
-+ return VM_FAULT_OOM;
-+ }
-+ else
-+ {
-+ struct VmaPageList *pVmaList;
-+
-+ get_page(pVmf->page);
-+ g_trackedPages++;
-+
-+ //find our vma in the list
-+ pVmaList = (struct VmaPageList *)pVma->vm_private_data;
-+
-+ if (pVmaList)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "vma found (%s %d)\n", current->comm, current->pid);
-+
-+ if (pVmaList->m_pPageTail->m_used == PAGES_PER_LIST)
-+ {
-+ PRINTK_VERBOSE(KERN_DEBUG "making new page list (%s %d)\n", current->comm, current->pid);
-+ //making a new page list
-+ pVmaList->m_pPageTail->m_pNext = (struct PageList *)kmalloc(sizeof(struct PageList), GFP_KERNEL);
-+ if (!pVmaList->m_pPageTail->m_pNext)
-+ return -ENOMEM;
-+
-+ //update the tail pointer
-+ pVmaList->m_pPageTail = pVmaList->m_pPageTail->m_pNext;
-+ pVmaList->m_pPageTail->m_used = 0;
-+ pVmaList->m_pPageTail->m_pNext = 0;
-+ }
-+
-+ PRINTK_VERBOSE(KERN_DEBUG "adding page to list (%s %d)\n", current->comm, current->pid);
-+
-+ pVmaList->m_pPageTail->m_pPages[pVmaList->m_pPageTail->m_used] = pVmf->page;
-+ pVmaList->m_pPageTail->m_used++;
-+ }
-+ else
-+ PRINTK(KERN_ERR "returned page for vma we don\'t know %p (%s %d)\n", pVma, current->comm, current->pid);
-+
-+ return 0;
-+ }
-+}
-+
-+/****** GENERIC FUNCTIONS ******/
-+static int __init dmaer_init(void)
-+{
-+ int result = alloc_chrdev_region(&g_majorMinor, 0, 1, "dmaer");
-+ if (result < 0)
-+ {
-+ PRINTK(KERN_ERR "unable to get major device number\n");
-+ return result;
-+ }
-+ else
-+ PRINTK(KERN_DEBUG "major device number %d\n", MAJOR(g_majorMinor));
-+
-+ PRINTK(KERN_DEBUG "vma list size %d, page list size %d, page size %ld\n",
-+ sizeof(struct VmaPageList), sizeof(struct PageList), PAGE_SIZE);
-+
-+ //get a dma channel to work with
-+ result = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST, (void **)&g_pDmaChanBase, &g_dmaIrq);
-+
-+ //uncomment to force to channel 0
-+ //result = 0;
-+ //g_pDmaChanBase = 0xce808000;
-+
-+ if (result < 0)
-+ {
-+ PRINTK(KERN_ERR "failed to allocate dma channel\n");
-+ cdev_del(&g_cDev);
-+ unregister_chrdev_region(g_majorMinor, 1);
-+ }
-+
-+ //reset the channel
-+ PRINTK(KERN_DEBUG "allocated dma channel %d (%p), initial state %08x\n", result, g_pDmaChanBase, *g_pDmaChanBase);
-+ *g_pDmaChanBase = 1 << 31;
-+ PRINTK(KERN_DEBUG "post-reset %08x\n", *g_pDmaChanBase);
-+
-+ g_dmaChan = result;
-+
-+ //clear the cache stats
-+ g_cacheHit = 0;
-+ g_cacheMiss = 0;
-+
-+ //register our device - after this we are go go go
-+ cdev_init(&g_cDev, &g_fOps);
-+ g_cDev.owner = THIS_MODULE;
-+ g_cDev.ops = &g_fOps;
-+
-+ result = cdev_add(&g_cDev, g_majorMinor, 1);
-+ if (result < 0)
-+ {
-+ PRINTK(KERN_ERR "failed to add character device\n");
-+ unregister_chrdev_region(g_majorMinor, 1);
-+ bcm_dma_chan_free(g_dmaChan);
-+ return result;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit dmaer_exit(void)
-+{
-+ PRINTK(KERN_INFO "closing dmaer device, cache stats: %d hits %d misses\n", g_cacheHit, g_cacheMiss);
-+ //unregister the device
-+ cdev_del(&g_cDev);
-+ unregister_chrdev_region(g_majorMinor, 1);
-+ //free the dma channel
-+ bcm_dma_chan_free(g_dmaChan);
-+}
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_AUTHOR("Simon Hall");
-+module_init(dmaer_init);
-+module_exit(dmaer_exit);
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/arm_control.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/arm_control.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/arm_control.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/arm_control.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,419 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/arm_control.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef __BCM2708_ARM_CONTROL_H
-+#define __BCM2708_ARM_CONTROL_H
-+
-+/*
-+ * Definitions and addresses for the ARM CONTROL logic
-+ * This file is manually generated.
-+ */
-+
-+#define ARM_BASE 0x7E00B000
-+
-+/* Basic configuration */
-+#define ARM_CONTROL0 HW_REGISTER_RW(ARM_BASE+0x000)
-+#define ARM_C0_SIZ128M 0x00000000
-+#define ARM_C0_SIZ256M 0x00000001
-+#define ARM_C0_SIZ512M 0x00000002
-+#define ARM_C0_SIZ1G 0x00000003
-+#define ARM_C0_BRESP0 0x00000000
-+#define ARM_C0_BRESP1 0x00000004
-+#define ARM_C0_BRESP2 0x00000008
-+#define ARM_C0_BOOTHI 0x00000010
-+#define ARM_C0_UNUSED05 0x00000020 /* free */
-+#define ARM_C0_FULLPERI 0x00000040
-+#define ARM_C0_UNUSED78 0x00000180 /* free */
-+#define ARM_C0_JTAGMASK 0x00000E00
-+#define ARM_C0_JTAGOFF 0x00000000
-+#define ARM_C0_JTAGBASH 0x00000800 /* Debug on GPIO off */
-+#define ARM_C0_JTAGGPIO 0x00000C00 /* Debug on GPIO on */
-+#define ARM_C0_APROTMSK 0x0000F000
-+#define ARM_C0_DBG0SYNC 0x00010000 /* VPU0 halt sync */
-+#define ARM_C0_DBG1SYNC 0x00020000 /* VPU1 halt sync */
-+#define ARM_C0_SWDBGREQ 0x00040000 /* HW debug request */
-+#define ARM_C0_PASSHALT 0x00080000 /* ARM halt passed to debugger */
-+#define ARM_C0_PRIO_PER 0x00F00000 /* per priority mask */
-+#define ARM_C0_PRIO_L2 0x0F000000
-+#define ARM_C0_PRIO_UC 0xF0000000
-+
-+#define ARM_C0_APROTPASS 0x0000A000 /* Translate 1:1 */
-+#define ARM_C0_APROTUSER 0x00000000 /* Only user mode */
-+#define ARM_C0_APROTSYST 0x0000F000 /* Only system mode */
-+
-+
-+#define ARM_CONTROL1 HW_REGISTER_RW(ARM_BASE+0x440)
-+#define ARM_C1_TIMER 0x00000001 /* re-route timer IRQ to VC */
-+#define ARM_C1_MAIL 0x00000002 /* re-route Mail IRQ to VC */
-+#define ARM_C1_BELL0 0x00000004 /* re-route Doorbell 0 to VC */
-+#define ARM_C1_BELL1 0x00000008 /* re-route Doorbell 1 to VC */
-+#define ARM_C1_PERSON 0x00000100 /* peripherals on */
-+#define ARM_C1_REQSTOP 0x00000200 /* ASYNC bridge request stop */
-+
-+#define ARM_STATUS HW_REGISTER_RW(ARM_BASE+0x444)
-+#define ARM_S_ACKSTOP 0x80000000 /* Bridge stopped */
-+#define ARM_S_READPEND 0x000003FF /* pending reads counter */
-+#define ARM_S_WRITPEND 0x000FFC00 /* pending writes counter */
-+
-+#define ARM_ERRHALT HW_REGISTER_RW(ARM_BASE+0x448)
-+#define ARM_EH_PERIBURST 0x00000001 /* Burst write seen on peri bus */
-+#define ARM_EH_ILLADDRS1 0x00000002 /* Address bits 25-27 error */
-+#define ARM_EH_ILLADDRS2 0x00000004 /* Address bits 31-28 error */
-+#define ARM_EH_VPU0HALT 0x00000008 /* VPU0 halted & in debug mode */
-+#define ARM_EH_VPU1HALT 0x00000010 /* VPU1 halted & in debug mode */
-+#define ARM_EH_ARMHALT 0x00000020 /* ARM in halted debug mode */
-+
-+#define ARM_ID_SECURE HW_REGISTER_RW(ARM_BASE+0x00C)
-+#define ARM_ID HW_REGISTER_RW(ARM_BASE+0x44C)
-+#define ARM_IDVAL 0x364D5241
-+
-+/* Translation memory */
-+#define ARM_TRANSLATE HW_REGISTER_RW(ARM_BASE+0x100)
-+/* 32 locations: 0x100.. 0x17F */
-+/* 32 spare means we CAN go to 64 pages.... */
-+
-+
-+/* Interrupts */
-+#define ARM_IRQ_PEND0 HW_REGISTER_RW(ARM_BASE+0x200) /* Top IRQ bits */
-+#define ARM_I0_TIMER 0x00000001 /* timer IRQ */
-+#define ARM_I0_MAIL 0x00000002 /* Mail IRQ */
-+#define ARM_I0_BELL0 0x00000004 /* Doorbell 0 */
-+#define ARM_I0_BELL1 0x00000008 /* Doorbell 1 */
-+#define ARM_I0_BANK1 0x00000100 /* Bank1 IRQ */
-+#define ARM_I0_BANK2 0x00000200 /* Bank2 IRQ */
-+
-+#define ARM_IRQ_PEND1 HW_REGISTER_RW(ARM_BASE+0x204) /* All bank1 IRQ bits */
-+/* todo: all I1_interrupt sources */
-+#define ARM_IRQ_PEND2 HW_REGISTER_RW(ARM_BASE+0x208) /* All bank2 IRQ bits */
-+/* todo: all I2_interrupt sources */
-+
-+#define ARM_IRQ_FAST HW_REGISTER_RW(ARM_BASE+0x20C) /* FIQ control */
-+#define ARM_IF_INDEX 0x0000007F /* FIQ select */
-+#define ARM_IF_ENABLE 0x00000080 /* FIQ enable */
-+#define ARM_IF_VCMASK 0x0000003F /* FIQ = (index from VC source) */
-+#define ARM_IF_TIMER 0x00000040 /* FIQ = ARM timer */
-+#define ARM_IF_MAIL 0x00000041 /* FIQ = ARM Mail */
-+#define ARM_IF_BELL0 0x00000042 /* FIQ = ARM Doorbell 0 */
-+#define ARM_IF_BELL1 0x00000043 /* FIQ = ARM Doorbell 1 */
-+#define ARM_IF_VP0HALT 0x00000044 /* FIQ = VPU0 Halt seen */
-+#define ARM_IF_VP1HALT 0x00000045 /* FIQ = VPU1 Halt seen */
-+#define ARM_IF_ILLEGAL 0x00000046 /* FIQ = Illegal access seen */
-+
-+#define ARM_IRQ_ENBL1 HW_REGISTER_RW(ARM_BASE+0x210) /* Bank1 enable bits */
-+#define ARM_IRQ_ENBL2 HW_REGISTER_RW(ARM_BASE+0x214) /* Bank2 enable bits */
-+#define ARM_IRQ_ENBL3 HW_REGISTER_RW(ARM_BASE+0x218) /* ARM irqs enable bits */
-+#define ARM_IRQ_DIBL1 HW_REGISTER_RW(ARM_BASE+0x21C) /* Bank1 disable bits */
-+#define ARM_IRQ_DIBL2 HW_REGISTER_RW(ARM_BASE+0x220) /* Bank2 disable bits */
-+#define ARM_IRQ_DIBL3 HW_REGISTER_RW(ARM_BASE+0x224) /* ARM irqs disable bits */
-+#define ARM_IE_TIMER 0x00000001 /* Timer IRQ */
-+#define ARM_IE_MAIL 0x00000002 /* Mail IRQ */
-+#define ARM_IE_BELL0 0x00000004 /* Doorbell 0 */
-+#define ARM_IE_BELL1 0x00000008 /* Doorbell 1 */
-+#define ARM_IE_VP0HALT 0x00000010 /* VPU0 Halt */
-+#define ARM_IE_VP1HALT 0x00000020 /* VPU1 Halt */
-+#define ARM_IE_ILLEGAL 0x00000040 /* Illegal access seen */
-+
-+/* Timer */
-+/* For reg. fields see sp804 spec. */
-+#define ARM_T_LOAD HW_REGISTER_RW(ARM_BASE+0x400)
-+#define ARM_T_VALUE HW_REGISTER_RW(ARM_BASE+0x404)
-+#define ARM_T_CONTROL HW_REGISTER_RW(ARM_BASE+0x408)
-+#define ARM_T_IRQCNTL HW_REGISTER_RW(ARM_BASE+0x40C)
-+#define ARM_T_RAWIRQ HW_REGISTER_RW(ARM_BASE+0x410)
-+#define ARM_T_MSKIRQ HW_REGISTER_RW(ARM_BASE+0x414)
-+#define ARM_T_RELOAD HW_REGISTER_RW(ARM_BASE+0x418)
-+#define ARM_T_PREDIV HW_REGISTER_RW(ARM_BASE+0x41c)
-+#define ARM_T_FREECNT HW_REGISTER_RW(ARM_BASE+0x420)
-+
-+#define TIMER_CTRL_ONESHOT (1 << 0)
-+#define TIMER_CTRL_32BIT (1 << 1)
-+#define TIMER_CTRL_DIV1 (0 << 2)
-+#define TIMER_CTRL_DIV16 (1 << 2)
-+#define TIMER_CTRL_DIV256 (2 << 2)
-+#define TIMER_CTRL_IE (1 << 5)
-+#define TIMER_CTRL_PERIODIC (1 << 6)
-+#define TIMER_CTRL_ENABLE (1 << 7)
-+#define TIMER_CTRL_DBGHALT (1 << 8)
-+#define TIMER_CTRL_ENAFREE (1 << 9)
-+#define TIMER_CTRL_FREEDIV_SHIFT 16)
-+#define TIMER_CTRL_FREEDIV_MASK 0xff
-+
-+/* Semaphores, Doorbells, Mailboxes */
-+#define ARM_SBM_OWN0 (ARM_BASE+0x800)
-+#define ARM_SBM_OWN1 (ARM_BASE+0x900)
-+#define ARM_SBM_OWN2 (ARM_BASE+0xA00)
-+#define ARM_SBM_OWN3 (ARM_BASE+0xB00)
-+
-+/* MAILBOXES
-+ * Register flags are common across all
-+ * owner registers. See end of this section
-+ *
-+ * Semaphores, Doorbells, Mailboxes Owner 0
-+ *
-+ */
-+
-+#define ARM_0_SEMS HW_REGISTER_RW(ARM_SBM_OWN0+0x00)
-+#define ARM_0_SEM0 HW_REGISTER_RW(ARM_SBM_OWN0+0x00)
-+#define ARM_0_SEM1 HW_REGISTER_RW(ARM_SBM_OWN0+0x04)
-+#define ARM_0_SEM2 HW_REGISTER_RW(ARM_SBM_OWN0+0x08)
-+#define ARM_0_SEM3 HW_REGISTER_RW(ARM_SBM_OWN0+0x0C)
-+#define ARM_0_SEM4 HW_REGISTER_RW(ARM_SBM_OWN0+0x10)
-+#define ARM_0_SEM5 HW_REGISTER_RW(ARM_SBM_OWN0+0x14)
-+#define ARM_0_SEM6 HW_REGISTER_RW(ARM_SBM_OWN0+0x18)
-+#define ARM_0_SEM7 HW_REGISTER_RW(ARM_SBM_OWN0+0x1C)
-+#define ARM_0_BELL0 HW_REGISTER_RW(ARM_SBM_OWN0+0x40)
-+#define ARM_0_BELL1 HW_REGISTER_RW(ARM_SBM_OWN0+0x44)
-+#define ARM_0_BELL2 HW_REGISTER_RW(ARM_SBM_OWN0+0x48)
-+#define ARM_0_BELL3 HW_REGISTER_RW(ARM_SBM_OWN0+0x4C)
-+/* MAILBOX 0 access in Owner 0 area */
-+/* Some addresses should ONLY be used by owner 0 */
-+#define ARM_0_MAIL0_WRT HW_REGISTER_RW(ARM_SBM_OWN0+0x80) /* .. 0x8C (4 locations) */
-+#define ARM_0_MAIL0_RD HW_REGISTER_RW(ARM_SBM_OWN0+0x80) /* .. 0x8C (4 locations) Normal read */
-+#define ARM_0_MAIL0_POL HW_REGISTER_RW(ARM_SBM_OWN0+0x90) /* none-pop read */
-+#define ARM_0_MAIL0_SND HW_REGISTER_RW(ARM_SBM_OWN0+0x94) /* Sender read (only LS 2 bits) */
-+#define ARM_0_MAIL0_STA HW_REGISTER_RW(ARM_SBM_OWN0+0x98) /* Status read */
-+#define ARM_0_MAIL0_CNF HW_REGISTER_RW(ARM_SBM_OWN0+0x9C) /* Config read/write */
-+/* MAILBOX 1 access in Owner 0 area */
-+/* Owner 0 should only WRITE to this mailbox */
-+#define ARM_0_MAIL1_WRT HW_REGISTER_RW(ARM_SBM_OWN0+0xA0) /* .. 0xAC (4 locations) */
-+/*#define ARM_0_MAIL1_RD HW_REGISTER_RW(ARM_SBM_OWN0+0xA0) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_0_MAIL1_POL HW_REGISTER_RW(ARM_SBM_OWN0+0xB0) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_0_MAIL1_SND HW_REGISTER_RW(ARM_SBM_OWN0+0xB4) */ /* DO NOT USE THIS !!!!! */
-+#define ARM_0_MAIL1_STA HW_REGISTER_RW(ARM_SBM_OWN0+0xB8) /* Status read */
-+/*#define ARM_0_MAIL1_CNF HW_REGISTER_RW(ARM_SBM_OWN0+0xBC) */ /* DO NOT USE THIS !!!!! */
-+/* General SEM, BELL, MAIL config/status */
-+#define ARM_0_SEMCLRDBG HW_REGISTER_RW(ARM_SBM_OWN0+0xE0) /* semaphore clear/debug register */
-+#define ARM_0_BELLCLRDBG HW_REGISTER_RW(ARM_SBM_OWN0+0xE4) /* Doorbells clear/debug register */
-+#define ARM_0_ALL_IRQS HW_REGISTER_RW(ARM_SBM_OWN0+0xF8) /* ALL interrupts */
-+#define ARM_0_MY_IRQS HW_REGISTER_RW(ARM_SBM_OWN0+0xFC) /* IRQS pending for owner 0 */
-+
-+/* Semaphores, Doorbells, Mailboxes Owner 1 */
-+#define ARM_1_SEMS HW_REGISTER_RW(ARM_SBM_OWN1+0x00)
-+#define ARM_1_SEM0 HW_REGISTER_RW(ARM_SBM_OWN1+0x00)
-+#define ARM_1_SEM1 HW_REGISTER_RW(ARM_SBM_OWN1+0x04)
-+#define ARM_1_SEM2 HW_REGISTER_RW(ARM_SBM_OWN1+0x08)
-+#define ARM_1_SEM3 HW_REGISTER_RW(ARM_SBM_OWN1+0x0C)
-+#define ARM_1_SEM4 HW_REGISTER_RW(ARM_SBM_OWN1+0x10)
-+#define ARM_1_SEM5 HW_REGISTER_RW(ARM_SBM_OWN1+0x14)
-+#define ARM_1_SEM6 HW_REGISTER_RW(ARM_SBM_OWN1+0x18)
-+#define ARM_1_SEM7 HW_REGISTER_RW(ARM_SBM_OWN1+0x1C)
-+#define ARM_1_BELL0 HW_REGISTER_RW(ARM_SBM_OWN1+0x40)
-+#define ARM_1_BELL1 HW_REGISTER_RW(ARM_SBM_OWN1+0x44)
-+#define ARM_1_BELL2 HW_REGISTER_RW(ARM_SBM_OWN1+0x48)
-+#define ARM_1_BELL3 HW_REGISTER_RW(ARM_SBM_OWN1+0x4C)
-+/* MAILBOX 0 access in Owner 0 area */
-+/* Owner 1 should only WRITE to this mailbox */
-+#define ARM_1_MAIL0_WRT HW_REGISTER_RW(ARM_SBM_OWN1+0x80) /* .. 0x8C (4 locations) */
-+/*#define ARM_1_MAIL0_RD HW_REGISTER_RW(ARM_SBM_OWN1+0x80) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_1_MAIL0_POL HW_REGISTER_RW(ARM_SBM_OWN1+0x90) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_1_MAIL0_SND HW_REGISTER_RW(ARM_SBM_OWN1+0x94) */ /* DO NOT USE THIS !!!!! */
-+#define ARM_1_MAIL0_STA HW_REGISTER_RW(ARM_SBM_OWN1+0x98) /* Status read */
-+/*#define ARM_1_MAIL0_CNF HW_REGISTER_RW(ARM_SBM_OWN1+0x9C) */ /* DO NOT USE THIS !!!!! */
-+/* MAILBOX 1 access in Owner 0 area */
-+#define ARM_1_MAIL1_WRT HW_REGISTER_RW(ARM_SBM_OWN1+0xA0) /* .. 0xAC (4 locations) */
-+#define ARM_1_MAIL1_RD HW_REGISTER_RW(ARM_SBM_OWN1+0xA0) /* .. 0xAC (4 locations) Normal read */
-+#define ARM_1_MAIL1_POL HW_REGISTER_RW(ARM_SBM_OWN1+0xB0) /* none-pop read */
-+#define ARM_1_MAIL1_SND HW_REGISTER_RW(ARM_SBM_OWN1+0xB4) /* Sender read (only LS 2 bits) */
-+#define ARM_1_MAIL1_STA HW_REGISTER_RW(ARM_SBM_OWN1+0xB8) /* Status read */
-+#define ARM_1_MAIL1_CNF HW_REGISTER_RW(ARM_SBM_OWN1+0xBC)
-+/* General SEM, BELL, MAIL config/status */
-+#define ARM_1_SEMCLRDBG HW_REGISTER_RW(ARM_SBM_OWN1+0xE0) /* semaphore clear/debug register */
-+#define ARM_1_BELLCLRDBG HW_REGISTER_RW(ARM_SBM_OWN1+0xE4) /* Doorbells clear/debug register */
-+#define ARM_1_MY_IRQS HW_REGISTER_RW(ARM_SBM_OWN1+0xFC) /* IRQS pending for owner 1 */
-+#define ARM_1_ALL_IRQS HW_REGISTER_RW(ARM_SBM_OWN1+0xF8) /* ALL interrupts */
-+
-+/* Semaphores, Doorbells, Mailboxes Owner 2 */
-+#define ARM_2_SEMS HW_REGISTER_RW(ARM_SBM_OWN2+0x00)
-+#define ARM_2_SEM0 HW_REGISTER_RW(ARM_SBM_OWN2+0x00)
-+#define ARM_2_SEM1 HW_REGISTER_RW(ARM_SBM_OWN2+0x04)
-+#define ARM_2_SEM2 HW_REGISTER_RW(ARM_SBM_OWN2+0x08)
-+#define ARM_2_SEM3 HW_REGISTER_RW(ARM_SBM_OWN2+0x0C)
-+#define ARM_2_SEM4 HW_REGISTER_RW(ARM_SBM_OWN2+0x10)
-+#define ARM_2_SEM5 HW_REGISTER_RW(ARM_SBM_OWN2+0x14)
-+#define ARM_2_SEM6 HW_REGISTER_RW(ARM_SBM_OWN2+0x18)
-+#define ARM_2_SEM7 HW_REGISTER_RW(ARM_SBM_OWN2+0x1C)
-+#define ARM_2_BELL0 HW_REGISTER_RW(ARM_SBM_OWN2+0x40)
-+#define ARM_2_BELL1 HW_REGISTER_RW(ARM_SBM_OWN2+0x44)
-+#define ARM_2_BELL2 HW_REGISTER_RW(ARM_SBM_OWN2+0x48)
-+#define ARM_2_BELL3 HW_REGISTER_RW(ARM_SBM_OWN2+0x4C)
-+/* MAILBOX 0 access in Owner 2 area */
-+/* Owner 2 should only WRITE to this mailbox */
-+#define ARM_2_MAIL0_WRT HW_REGISTER_RW(ARM_SBM_OWN2+0x80) /* .. 0x8C (4 locations) */
-+/*#define ARM_2_MAIL0_RD HW_REGISTER_RW(ARM_SBM_OWN2+0x80) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_2_MAIL0_POL HW_REGISTER_RW(ARM_SBM_OWN2+0x90) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_2_MAIL0_SND HW_REGISTER_RW(ARM_SBM_OWN2+0x94) */ /* DO NOT USE THIS !!!!! */
-+#define ARM_2_MAIL0_STA HW_REGISTER_RW(ARM_SBM_OWN2+0x98) /* Status read */
-+/*#define ARM_2_MAIL0_CNF HW_REGISTER_RW(ARM_SBM_OWN2+0x9C) */ /* DO NOT USE THIS !!!!! */
-+/* MAILBOX 1 access in Owner 2 area */
-+/* Owner 2 should only WRITE to this mailbox */
-+#define ARM_2_MAIL1_WRT HW_REGISTER_RW(ARM_SBM_OWN2+0xA0) /* .. 0xAC (4 locations) */
-+/*#define ARM_2_MAIL1_RD HW_REGISTER_RW(ARM_SBM_OWN2+0xA0) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_2_MAIL1_POL HW_REGISTER_RW(ARM_SBM_OWN2+0xB0) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_2_MAIL1_SND HW_REGISTER_RW(ARM_SBM_OWN2+0xB4) */ /* DO NOT USE THIS !!!!! */
-+#define ARM_2_MAIL1_STA HW_REGISTER_RW(ARM_SBM_OWN2+0xB8) /* Status read */
-+/*#define ARM_2_MAIL1_CNF HW_REGISTER_RW(ARM_SBM_OWN2+0xBC) */ /* DO NOT USE THIS !!!!! */
-+/* General SEM, BELL, MAIL config/status */
-+#define ARM_2_SEMCLRDBG HW_REGISTER_RW(ARM_SBM_OWN2+0xE0) /* semaphore clear/debug register */
-+#define ARM_2_BELLCLRDBG HW_REGISTER_RW(ARM_SBM_OWN2+0xE4) /* Doorbells clear/debug register */
-+#define ARM_2_MY_IRQS HW_REGISTER_RW(ARM_SBM_OWN2+0xFC) /* IRQS pending for owner 2 */
-+#define ARM_2_ALL_IRQS HW_REGISTER_RW(ARM_SBM_OWN2+0xF8) /* ALL interrupts */
-+
-+/* Semaphores, Doorbells, Mailboxes Owner 3 */
-+#define ARM_3_SEMS HW_REGISTER_RW(ARM_SBM_OWN3+0x00)
-+#define ARM_3_SEM0 HW_REGISTER_RW(ARM_SBM_OWN3+0x00)
-+#define ARM_3_SEM1 HW_REGISTER_RW(ARM_SBM_OWN3+0x04)
-+#define ARM_3_SEM2 HW_REGISTER_RW(ARM_SBM_OWN3+0x08)
-+#define ARM_3_SEM3 HW_REGISTER_RW(ARM_SBM_OWN3+0x0C)
-+#define ARM_3_SEM4 HW_REGISTER_RW(ARM_SBM_OWN3+0x10)
-+#define ARM_3_SEM5 HW_REGISTER_RW(ARM_SBM_OWN3+0x14)
-+#define ARM_3_SEM6 HW_REGISTER_RW(ARM_SBM_OWN3+0x18)
-+#define ARM_3_SEM7 HW_REGISTER_RW(ARM_SBM_OWN3+0x1C)
-+#define ARM_3_BELL0 HW_REGISTER_RW(ARM_SBM_OWN3+0x40)
-+#define ARM_3_BELL1 HW_REGISTER_RW(ARM_SBM_OWN3+0x44)
-+#define ARM_3_BELL2 HW_REGISTER_RW(ARM_SBM_OWN3+0x48)
-+#define ARM_3_BELL3 HW_REGISTER_RW(ARM_SBM_OWN3+0x4C)
-+/* MAILBOX 0 access in Owner 3 area */
-+/* Owner 3 should only WRITE to this mailbox */
-+#define ARM_3_MAIL0_WRT HW_REGISTER_RW(ARM_SBM_OWN3+0x80) /* .. 0x8C (4 locations) */
-+/*#define ARM_3_MAIL0_RD HW_REGISTER_RW(ARM_SBM_OWN3+0x80) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_3_MAIL0_POL HW_REGISTER_RW(ARM_SBM_OWN3+0x90) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_3_MAIL0_SND HW_REGISTER_RW(ARM_SBM_OWN3+0x94) */ /* DO NOT USE THIS !!!!! */
-+#define ARM_3_MAIL0_STA HW_REGISTER_RW(ARM_SBM_OWN3+0x98) /* Status read */
-+/*#define ARM_3_MAIL0_CNF HW_REGISTER_RW(ARM_SBM_OWN3+0x9C) */ /* DO NOT USE THIS !!!!! */
-+/* MAILBOX 1 access in Owner 3 area */
-+/* Owner 3 should only WRITE to this mailbox */
-+#define ARM_3_MAIL1_WRT HW_REGISTER_RW(ARM_SBM_OWN3+0xA0) /* .. 0xAC (4 locations) */
-+/*#define ARM_3_MAIL1_RD HW_REGISTER_RW(ARM_SBM_OWN3+0xA0) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_3_MAIL1_POL HW_REGISTER_RW(ARM_SBM_OWN3+0xB0) */ /* DO NOT USE THIS !!!!! */
-+/*#define ARM_3_MAIL1_SND HW_REGISTER_RW(ARM_SBM_OWN3+0xB4) */ /* DO NOT USE THIS !!!!! */
-+#define ARM_3_MAIL1_STA HW_REGISTER_RW(ARM_SBM_OWN3+0xB8) /* Status read */
-+/*#define ARM_3_MAIL1_CNF HW_REGISTER_RW(ARM_SBM_OWN3+0xBC) */ /* DO NOT USE THIS !!!!! */
-+/* General SEM, BELL, MAIL config/status */
-+#define ARM_3_SEMCLRDBG HW_REGISTER_RW(ARM_SBM_OWN3+0xE0) /* semaphore clear/debug register */
-+#define ARM_3_BELLCLRDBG HW_REGISTER_RW(ARM_SBM_OWN3+0xE4) /* Doorbells clear/debug register */
-+#define ARM_3_MY_IRQS HW_REGISTER_RW(ARM_SBM_OWN3+0xFC) /* IRQS pending for owner 3 */
-+#define ARM_3_ALL_IRQS HW_REGISTER_RW(ARM_SBM_OWN3+0xF8) /* ALL interrupts */
-+
-+
-+
-+/* Mailbox flags. Valid for all owners */
-+
-+/* Mailbox status register (...0x98) */
-+#define ARM_MS_FULL 0x80000000
-+#define ARM_MS_EMPTY 0x40000000
-+#define ARM_MS_LEVEL 0x400000FF /* Max. value depdnds on mailbox depth parameter */
-+
-+/* MAILBOX config/status register (...0x9C) */
-+/* ANY write to this register clears the error bits! */
-+#define ARM_MC_IHAVEDATAIRQEN 0x00000001 /* mailbox irq enable: has data */
-+#define ARM_MC_IHAVESPACEIRQEN 0x00000002 /* mailbox irq enable: has space */
-+#define ARM_MC_OPPISEMPTYIRQEN 0x00000004 /* mailbox irq enable: Opp. is empty */
-+#define ARM_MC_MAIL_CLEAR 0x00000008 /* mailbox clear write 1, then 0 */
-+#define ARM_MC_IHAVEDATAIRQPEND 0x00000010 /* mailbox irq pending: has space */
-+#define ARM_MC_IHAVESPACEIRQPEND 0x00000020 /* mailbox irq pending: Opp. is empty */
-+#define ARM_MC_OPPISEMPTYIRQPEND 0x00000040 /* mailbox irq pending */
-+/* Bit 7 is unused */
-+#define ARM_MC_ERRNOOWN 0x00000100 /* error : none owner read from mailbox */
-+#define ARM_MC_ERROVERFLW 0x00000200 /* error : write to fill mailbox */
-+#define ARM_MC_ERRUNDRFLW 0x00000400 /* error : read from empty mailbox */
-+
-+/* Semaphore clear/debug register (...0xE0) */
-+#define ARM_SD_OWN0 0x00000003 /* Owner of sem 0 */
-+#define ARM_SD_OWN1 0x0000000C /* Owner of sem 1 */
-+#define ARM_SD_OWN2 0x00000030 /* Owner of sem 2 */
-+#define ARM_SD_OWN3 0x000000C0 /* Owner of sem 3 */
-+#define ARM_SD_OWN4 0x00000300 /* Owner of sem 4 */
-+#define ARM_SD_OWN5 0x00000C00 /* Owner of sem 5 */
-+#define ARM_SD_OWN6 0x00003000 /* Owner of sem 6 */
-+#define ARM_SD_OWN7 0x0000C000 /* Owner of sem 7 */
-+#define ARM_SD_SEM0 0x00010000 /* Status of sem 0 */
-+#define ARM_SD_SEM1 0x00020000 /* Status of sem 1 */
-+#define ARM_SD_SEM2 0x00040000 /* Status of sem 2 */
-+#define ARM_SD_SEM3 0x00080000 /* Status of sem 3 */
-+#define ARM_SD_SEM4 0x00100000 /* Status of sem 4 */
-+#define ARM_SD_SEM5 0x00200000 /* Status of sem 5 */
-+#define ARM_SD_SEM6 0x00400000 /* Status of sem 6 */
-+#define ARM_SD_SEM7 0x00800000 /* Status of sem 7 */
-+
-+/* Doorbells clear/debug register (...0xE4) */
-+#define ARM_BD_OWN0 0x00000003 /* Owner of doorbell 0 */
-+#define ARM_BD_OWN1 0x0000000C /* Owner of doorbell 1 */
-+#define ARM_BD_OWN2 0x00000030 /* Owner of doorbell 2 */
-+#define ARM_BD_OWN3 0x000000C0 /* Owner of doorbell 3 */
-+#define ARM_BD_BELL0 0x00000100 /* Status of doorbell 0 */
-+#define ARM_BD_BELL1 0x00000200 /* Status of doorbell 1 */
-+#define ARM_BD_BELL2 0x00000400 /* Status of doorbell 2 */
-+#define ARM_BD_BELL3 0x00000800 /* Status of doorbell 3 */
-+
-+/* MY IRQS register (...0xF8) */
-+#define ARM_MYIRQ_BELL 0x00000001 /* This owner has a doorbell IRQ */
-+#define ARM_MYIRQ_MAIL 0x00000002 /* This owner has a mailbox IRQ */
-+
-+/* ALL IRQS register (...0xF8) */
-+#define ARM_AIS_BELL0 0x00000001 /* Doorbell 0 IRQ pending */
-+#define ARM_AIS_BELL1 0x00000002 /* Doorbell 1 IRQ pending */
-+#define ARM_AIS_BELL2 0x00000004 /* Doorbell 2 IRQ pending */
-+#define ARM_AIS_BELL3 0x00000008 /* Doorbell 3 IRQ pending */
-+#define ARM_AIS0_HAVEDATA 0x00000010 /* MAIL 0 has data IRQ pending */
-+#define ARM_AIS0_HAVESPAC 0x00000020 /* MAIL 0 has space IRQ pending */
-+#define ARM_AIS0_OPPEMPTY 0x00000040 /* MAIL 0 opposite is empty IRQ */
-+#define ARM_AIS1_HAVEDATA 0x00000080 /* MAIL 1 has data IRQ pending */
-+#define ARM_AIS1_HAVESPAC 0x00000100 /* MAIL 1 has space IRQ pending */
-+#define ARM_AIS1_OPPEMPTY 0x00000200 /* MAIL 1 opposite is empty IRQ */
-+/* Note that bell-0, bell-1 and MAIL0 IRQ go only to the ARM */
-+/* Whilst that bell-2, bell-3 and MAIL1 IRQ go only to the VC */
-+/* */
-+/* ARM JTAG BASH */
-+/* */
-+#define AJB_BASE 0x7e2000c0
-+
-+#define AJBCONF HW_REGISTER_RW(AJB_BASE+0x00)
-+#define AJB_BITS0 0x000000
-+#define AJB_BITS4 0x000004
-+#define AJB_BITS8 0x000008
-+#define AJB_BITS12 0x00000C
-+#define AJB_BITS16 0x000010
-+#define AJB_BITS20 0x000014
-+#define AJB_BITS24 0x000018
-+#define AJB_BITS28 0x00001C
-+#define AJB_BITS32 0x000020
-+#define AJB_BITS34 0x000022
-+#define AJB_OUT_MS 0x000040
-+#define AJB_OUT_LS 0x000000
-+#define AJB_INV_CLK 0x000080
-+#define AJB_D0_RISE 0x000100
-+#define AJB_D0_FALL 0x000000
-+#define AJB_D1_RISE 0x000200
-+#define AJB_D1_FALL 0x000000
-+#define AJB_IN_RISE 0x000400
-+#define AJB_IN_FALL 0x000000
-+#define AJB_ENABLE 0x000800
-+#define AJB_HOLD0 0x000000
-+#define AJB_HOLD1 0x001000
-+#define AJB_HOLD2 0x002000
-+#define AJB_HOLD3 0x003000
-+#define AJB_RESETN 0x004000
-+#define AJB_CLKSHFT 16
-+#define AJB_BUSY 0x80000000
-+#define AJBTMS HW_REGISTER_RW(AJB_BASE+0x04)
-+#define AJBTDI HW_REGISTER_RW(AJB_BASE+0x08)
-+#define AJBTDO HW_REGISTER_RW(AJB_BASE+0x0c)
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/arm_power.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/arm_power.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/arm_power.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/arm_power.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,60 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/include/mach/arm_power.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef _ARM_POWER_H
-+#define _ARM_POWER_H
-+
-+/* Use meaningful names on each side */
-+#ifdef __VIDEOCORE__
-+#define PREFIX(x) ARM_##x
-+#else
-+#define PREFIX(x) BCM_##x
-+#endif
-+
-+enum {
-+ PREFIX(POWER_SDCARD_BIT),
-+ PREFIX(POWER_UART_BIT),
-+ PREFIX(POWER_MINIUART_BIT),
-+ PREFIX(POWER_USB_BIT),
-+ PREFIX(POWER_I2C0_BIT),
-+ PREFIX(POWER_I2C1_BIT),
-+ PREFIX(POWER_I2C2_BIT),
-+ PREFIX(POWER_SPI_BIT),
-+ PREFIX(POWER_CCP2TX_BIT),
-+
-+ PREFIX(POWER_MAX)
-+};
-+
-+enum {
-+ PREFIX(POWER_SDCARD) = (1 << PREFIX(POWER_SDCARD_BIT)),
-+ PREFIX(POWER_UART) = (1 << PREFIX(POWER_UART_BIT)),
-+ PREFIX(POWER_MINIUART) = (1 << PREFIX(POWER_MINIUART_BIT)),
-+ PREFIX(POWER_USB) = (1 << PREFIX(POWER_USB_BIT)),
-+ PREFIX(POWER_I2C0) = (1 << PREFIX(POWER_I2C0_BIT)),
-+ PREFIX(POWER_I2C1_MASK) = (1 << PREFIX(POWER_I2C1_BIT)),
-+ PREFIX(POWER_I2C2_MASK) = (1 << PREFIX(POWER_I2C2_BIT)),
-+ PREFIX(POWER_SPI_MASK) = (1 << PREFIX(POWER_SPI_BIT)),
-+ PREFIX(POWER_CCP2TX_MASK) = (1 << PREFIX(POWER_CCP2TX_BIT)),
-+
-+ PREFIX(POWER_MASK) = (1 << PREFIX(POWER_MAX)) - 1,
-+ PREFIX(POWER_NONE) = 0
-+};
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/clkdev.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/clkdev.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/clkdev.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/clkdev.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,7 @@
-+#ifndef __ASM_MACH_CLKDEV_H
-+#define __ASM_MACH_CLKDEV_H
-+
-+#define __clk_get(clk) ({ 1; })
-+#define __clk_put(clk) do { } while (0)
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/debug-macro.S linux-3.11.10/arch/arm/mach-bcm2708/include/mach/debug-macro.S
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/debug-macro.S 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/debug-macro.S 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,22 @@
-+/* arch/arm/mach-bcm2708/include/mach/debug-macro.S
-+ *
-+ * Debugging macro include header
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ * Copyright (C) 1994-1999 Russell King
-+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
-+ *
-+ * 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 <mach/platform.h>
-+
-+ .macro addruart, rp, rv, tmp
-+ ldr \rp, =UART0_BASE
-+ ldr \rv, =IO_ADDRESS(UART0_BASE)
-+ .endm
-+
-+#include <asm/hardware/debug-pl01x.S>
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/dma.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/dma.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/dma.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/dma.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,86 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/include/mach/dma.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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 _MACH_BCM2708_DMA_H
-+#define _MACH_BCM2708_DMA_H
-+
-+#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma"
-+
-+/* DMA CS Control and Status bits */
-+#define BCM2708_DMA_ACTIVE (1 << 0)
-+#define BCM2708_DMA_INT (1 << 2)
-+#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
-+#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
-+#define BCM2708_DMA_ERR (1 << 8)
-+#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
-+#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */
-+
-+/* DMA control block "info" field bits */
-+#define BCM2708_DMA_INT_EN (1 << 0)
-+#define BCM2708_DMA_TDMODE (1 << 1)
-+#define BCM2708_DMA_WAIT_RESP (1 << 3)
-+#define BCM2708_DMA_D_INC (1 << 4)
-+#define BCM2708_DMA_D_WIDTH (1 << 5)
-+#define BCM2708_DMA_D_DREQ (1 << 6)
-+#define BCM2708_DMA_S_INC (1 << 8)
-+#define BCM2708_DMA_S_WIDTH (1 << 9)
-+#define BCM2708_DMA_S_DREQ (1 << 10)
-+
-+#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12)
-+#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
-+#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21)
-+
-+#define BCM2708_DMA_DREQ_EMMC 11
-+#define BCM2708_DMA_DREQ_SDHOST 13
-+
-+#define BCM2708_DMA_CS 0x00 /* Control and Status */
-+#define BCM2708_DMA_ADDR 0x04
-+/* the current control block appears in the following registers - read only */
-+#define BCM2708_DMA_INFO 0x08
-+#define BCM2708_DMA_NEXTCB 0x1C
-+#define BCM2708_DMA_DEBUG 0x20
-+
-+#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS)
-+#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR)
-+
-+#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
-+
-+struct bcm2708_dma_cb {
-+ unsigned long info;
-+ unsigned long src;
-+ unsigned long dst;
-+ unsigned long length;
-+ unsigned long stride;
-+ unsigned long next;
-+ unsigned long pad[2];
-+};
-+
-+extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
-+extern void bcm_dma_start(void __iomem *dma_chan_base,
-+ dma_addr_t control_block);
-+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base);
-+extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base);
-+
-+/* When listing features we can ask for when allocating DMA channels give
-+ those with higher priority smaller ordinal numbers */
-+#define BCM_DMA_FEATURE_FAST_ORD 0
-+#define BCM_DMA_FEATURE_BULK_ORD 1
-+#define BCM_DMA_FEATURE_FAST (1<<BCM_DMA_FEATURE_FAST_ORD)
-+#define BCM_DMA_FEATURE_BULK (1<<BCM_DMA_FEATURE_BULK_ORD)
-+#define BCM_DMA_FEATURE_COUNT 2
-+
-+/* return channel no or -ve error */
-+extern int bcm_dma_chan_alloc(unsigned preferred_feature_set,
-+ void __iomem **out_dma_base, int *out_dma_irq);
-+extern int bcm_dma_chan_free(int channel);
-+
-+
-+#endif /* _MACH_BCM2708_DMA_H */
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/entry-macro.S linux-3.11.10/arch/arm/mach-bcm2708/include/mach/entry-macro.S
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/entry-macro.S 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/entry-macro.S 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,69 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/entry-macro.S
-+ *
-+ * Low-level IRQ helper macros for BCM2708 platforms
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#include <mach/hardware.h>
-+
-+ .macro disable_fiq
-+ .endm
-+
-+ .macro get_irqnr_preamble, base, tmp
-+ ldr \base, =IO_ADDRESS(ARMCTRL_IC_BASE)
-+ .endm
-+
-+ .macro arch_ret_to_user, tmp1, tmp2
-+ .endm
-+
-+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-+ /* get masked status */
-+ ldr \irqstat, [\base, #(ARM_IRQ_PEND0 - ARMCTRL_IC_BASE)]
-+ mov \irqnr, #(ARM_IRQ0_BASE + 31)
-+ and \tmp, \irqstat, #0x300 @ save bits 8 and 9
-+ /* clear bits 8 and 9, and test */
-+ bics \irqstat, \irqstat, #0x300
-+ bne 1010f
-+
-+ tst \tmp, #0x100
-+ ldrne \irqstat, [\base, #(ARM_IRQ_PEND1 - ARMCTRL_IC_BASE)]
-+ movne \irqnr, #(ARM_IRQ1_BASE + 31)
-+ @ Mask out the interrupts also present in PEND0 - see SW-5809
-+ bicne \irqstat, #((1<<7) | (1<<9) | (1<<10))
-+ bicne \irqstat, #((1<<18) | (1<<19))
-+ bne 1010f
-+
-+ tst \tmp, #0x200
-+ ldrne \irqstat, [\base, #(ARM_IRQ_PEND2 - ARMCTRL_IC_BASE)]
-+ movne \irqnr, #(ARM_IRQ2_BASE + 31)
-+ @ Mask out the interrupts also present in PEND0 - see SW-5809
-+ bicne \irqstat, #((1<<21) | (1<<22) | (1<<23) | (1<<24) | (1<<25))
-+ bicne \irqstat, #((1<<30))
-+ beq 1020f
-+
-+1010:
-+ @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
-+ @ N.B. CLZ is an ARM5 instruction.
-+ sub \tmp, \irqstat, #1
-+ eor \irqstat, \irqstat, \tmp
-+ clz \tmp, \irqstat
-+ sub \irqnr, \tmp
-+
-+1020: @ EQ will be set if no irqs pending
-+
-+ .endm
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/frc.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/frc.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/frc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/frc.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,38 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/timex.h
-+ *
-+ * BCM2708 free running counter (timer)
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef _MACH_FRC_H
-+#define _MACH_FRC_H
-+
-+#define FRC_TICK_RATE (1000000)
-+
-+/*! Free running counter incrementing at the CLOCK_TICK_RATE
-+ (slightly faster than frc_clock_ticks63()
-+ */
-+extern unsigned long frc_clock_ticks32(void);
-+
-+/*! Free running counter incrementing at the CLOCK_TICK_RATE
-+ * Note - top bit should be ignored (see cnt32_to_63)
-+ */
-+extern unsigned long long frc_clock_ticks63(void);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/gpio.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/gpio.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/gpio.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/gpio.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,17 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/gpio.h
-+ *
-+ * This file is licensed under the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#ifndef __ASM_ARCH_GPIO_H
-+#define __ASM_ARCH_GPIO_H
-+
-+#define ARCH_NR_GPIOS 54 // number of gpio lines
-+
-+#define gpio_to_irq(x) ((x) + GPIO_IRQ_START)
-+#define irq_to_gpio(x) ((x) - GPIO_IRQ_START)
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/hardware.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/hardware.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/hardware.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/hardware.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,28 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/hardware.h
-+ *
-+ * This file contains the hardware definitions of the BCM2708 devices.
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ASM_ARCH_HARDWARE_H
-+#define __ASM_ARCH_HARDWARE_H
-+
-+#include <asm/sizes.h>
-+#include <mach/platform.h>
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/io.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/io.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/io.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/io.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,27 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/io.h
-+ *
-+ * Copyright (C) 2003 ARM Limited
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ASM_ARM_ARCH_IO_H
-+#define __ASM_ARM_ARCH_IO_H
-+
-+#define IO_SPACE_LIMIT 0xffffffff
-+
-+#define __io(a) __typesafe_io(a)
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/irqs.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/irqs.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/irqs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/irqs.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,199 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/irqs.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ * Copyright (C) 2003 ARM Limited
-+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef _BCM2708_IRQS_H_
-+#define _BCM2708_IRQS_H_
-+
-+#include <mach/platform.h>
-+
-+/*
-+ * IRQ interrupts definitions are the same as the INT definitions
-+ * held within platform.h
-+ */
-+#define IRQ_ARMCTRL_START 0
-+#define IRQ_TIMER0 (IRQ_ARMCTRL_START + INTERRUPT_TIMER0)
-+#define IRQ_TIMER1 (IRQ_ARMCTRL_START + INTERRUPT_TIMER1)
-+#define IRQ_TIMER2 (IRQ_ARMCTRL_START + INTERRUPT_TIMER2)
-+#define IRQ_TIMER3 (IRQ_ARMCTRL_START + INTERRUPT_TIMER3)
-+#define IRQ_CODEC0 (IRQ_ARMCTRL_START + INTERRUPT_CODEC0)
-+#define IRQ_CODEC1 (IRQ_ARMCTRL_START + INTERRUPT_CODEC1)
-+#define IRQ_CODEC2 (IRQ_ARMCTRL_START + INTERRUPT_CODEC2)
-+#define IRQ_JPEG (IRQ_ARMCTRL_START + INTERRUPT_JPEG)
-+#define IRQ_ISP (IRQ_ARMCTRL_START + INTERRUPT_ISP)
-+#define IRQ_USB (IRQ_ARMCTRL_START + INTERRUPT_USB)
-+#define IRQ_3D (IRQ_ARMCTRL_START + INTERRUPT_3D)
-+#define IRQ_TRANSPOSER (IRQ_ARMCTRL_START + INTERRUPT_TRANSPOSER)
-+#define IRQ_MULTICORESYNC0 (IRQ_ARMCTRL_START + INTERRUPT_MULTICORESYNC0)
-+#define IRQ_MULTICORESYNC1 (IRQ_ARMCTRL_START + INTERRUPT_MULTICORESYNC1)
-+#define IRQ_MULTICORESYNC2 (IRQ_ARMCTRL_START + INTERRUPT_MULTICORESYNC2)
-+#define IRQ_MULTICORESYNC3 (IRQ_ARMCTRL_START + INTERRUPT_MULTICORESYNC3)
-+#define IRQ_DMA0 (IRQ_ARMCTRL_START + INTERRUPT_DMA0)
-+#define IRQ_DMA1 (IRQ_ARMCTRL_START + INTERRUPT_DMA1)
-+#define IRQ_DMA2 (IRQ_ARMCTRL_START + INTERRUPT_DMA2)
-+#define IRQ_DMA3 (IRQ_ARMCTRL_START + INTERRUPT_DMA3)
-+#define IRQ_DMA4 (IRQ_ARMCTRL_START + INTERRUPT_DMA4)
-+#define IRQ_DMA5 (IRQ_ARMCTRL_START + INTERRUPT_DMA5)
-+#define IRQ_DMA6 (IRQ_ARMCTRL_START + INTERRUPT_DMA6)
-+#define IRQ_DMA7 (IRQ_ARMCTRL_START + INTERRUPT_DMA7)
-+#define IRQ_DMA8 (IRQ_ARMCTRL_START + INTERRUPT_DMA8)
-+#define IRQ_DMA9 (IRQ_ARMCTRL_START + INTERRUPT_DMA9)
-+#define IRQ_DMA10 (IRQ_ARMCTRL_START + INTERRUPT_DMA10)
-+#define IRQ_DMA11 (IRQ_ARMCTRL_START + INTERRUPT_DMA11)
-+#define IRQ_DMA12 (IRQ_ARMCTRL_START + INTERRUPT_DMA12)
-+#define IRQ_AUX (IRQ_ARMCTRL_START + INTERRUPT_AUX)
-+#define IRQ_ARM (IRQ_ARMCTRL_START + INTERRUPT_ARM)
-+#define IRQ_VPUDMA (IRQ_ARMCTRL_START + INTERRUPT_VPUDMA)
-+#define IRQ_HOSTPORT (IRQ_ARMCTRL_START + INTERRUPT_HOSTPORT)
-+#define IRQ_VIDEOSCALER (IRQ_ARMCTRL_START + INTERRUPT_VIDEOSCALER)
-+#define IRQ_CCP2TX (IRQ_ARMCTRL_START + INTERRUPT_CCP2TX)
-+#define IRQ_SDC (IRQ_ARMCTRL_START + INTERRUPT_SDC)
-+#define IRQ_DSI0 (IRQ_ARMCTRL_START + INTERRUPT_DSI0)
-+#define IRQ_AVE (IRQ_ARMCTRL_START + INTERRUPT_AVE)
-+#define IRQ_CAM0 (IRQ_ARMCTRL_START + INTERRUPT_CAM0)
-+#define IRQ_CAM1 (IRQ_ARMCTRL_START + INTERRUPT_CAM1)
-+#define IRQ_HDMI0 (IRQ_ARMCTRL_START + INTERRUPT_HDMI0)
-+#define IRQ_HDMI1 (IRQ_ARMCTRL_START + INTERRUPT_HDMI1)
-+#define IRQ_PIXELVALVE1 (IRQ_ARMCTRL_START + INTERRUPT_PIXELVALVE1)
-+#define IRQ_I2CSPISLV (IRQ_ARMCTRL_START + INTERRUPT_I2CSPISLV)
-+#define IRQ_DSI1 (IRQ_ARMCTRL_START + INTERRUPT_DSI1)
-+#define IRQ_PWA0 (IRQ_ARMCTRL_START + INTERRUPT_PWA0)
-+#define IRQ_PWA1 (IRQ_ARMCTRL_START + INTERRUPT_PWA1)
-+#define IRQ_CPR (IRQ_ARMCTRL_START + INTERRUPT_CPR)
-+#define IRQ_SMI (IRQ_ARMCTRL_START + INTERRUPT_SMI)
-+#define IRQ_GPIO0 (IRQ_ARMCTRL_START + INTERRUPT_GPIO0)
-+#define IRQ_GPIO1 (IRQ_ARMCTRL_START + INTERRUPT_GPIO1)
-+#define IRQ_GPIO2 (IRQ_ARMCTRL_START + INTERRUPT_GPIO2)
-+#define IRQ_GPIO3 (IRQ_ARMCTRL_START + INTERRUPT_GPIO3)
-+#define IRQ_I2C (IRQ_ARMCTRL_START + INTERRUPT_I2C)
-+#define IRQ_SPI (IRQ_ARMCTRL_START + INTERRUPT_SPI)
-+#define IRQ_I2SPCM (IRQ_ARMCTRL_START + INTERRUPT_I2SPCM)
-+#define IRQ_SDIO (IRQ_ARMCTRL_START + INTERRUPT_SDIO)
-+#define IRQ_UART (IRQ_ARMCTRL_START + INTERRUPT_UART)
-+#define IRQ_SLIMBUS (IRQ_ARMCTRL_START + INTERRUPT_SLIMBUS)
-+#define IRQ_VEC (IRQ_ARMCTRL_START + INTERRUPT_VEC)
-+#define IRQ_CPG (IRQ_ARMCTRL_START + INTERRUPT_CPG)
-+#define IRQ_RNG (IRQ_ARMCTRL_START + INTERRUPT_RNG)
-+#define IRQ_ARASANSDIO (IRQ_ARMCTRL_START + INTERRUPT_ARASANSDIO)
-+#define IRQ_AVSPMON (IRQ_ARMCTRL_START + INTERRUPT_AVSPMON)
-+
-+#define IRQ_ARM_TIMER (IRQ_ARMCTRL_START + INTERRUPT_ARM_TIMER)
-+#define IRQ_ARM_MAILBOX (IRQ_ARMCTRL_START + INTERRUPT_ARM_MAILBOX)
-+#define IRQ_ARM_DOORBELL_0 (IRQ_ARMCTRL_START + INTERRUPT_ARM_DOORBELL_0)
-+#define IRQ_ARM_DOORBELL_1 (IRQ_ARMCTRL_START + INTERRUPT_ARM_DOORBELL_1)
-+#define IRQ_VPU0_HALTED (IRQ_ARMCTRL_START + INTERRUPT_VPU0_HALTED)
-+#define IRQ_VPU1_HALTED (IRQ_ARMCTRL_START + INTERRUPT_VPU1_HALTED)
-+#define IRQ_ILLEGAL_TYPE0 (IRQ_ARMCTRL_START + INTERRUPT_ILLEGAL_TYPE0)
-+#define IRQ_ILLEGAL_TYPE1 (IRQ_ARMCTRL_START + INTERRUPT_ILLEGAL_TYPE1)
-+#define IRQ_PENDING1 (IRQ_ARMCTRL_START + INTERRUPT_PENDING1)
-+#define IRQ_PENDING2 (IRQ_ARMCTRL_START + INTERRUPT_PENDING2)
-+
-+#define FIQ_START HARD_IRQS
-+
-+/*
-+ * FIQ interrupts definitions are the same as the INT definitions.
-+ */
-+#define FIQ_TIMER0 (FIQ_START+INTERRUPT_TIMER0)
-+#define FIQ_TIMER1 (FIQ_START+INTERRUPT_TIMER1)
-+#define FIQ_TIMER2 (FIQ_START+INTERRUPT_TIMER2)
-+#define FIQ_TIMER3 (FIQ_START+INTERRUPT_TIMER3)
-+#define FIQ_CODEC0 (FIQ_START+INTERRUPT_CODEC0)
-+#define FIQ_CODEC1 (FIQ_START+INTERRUPT_CODEC1)
-+#define FIQ_CODEC2 (FIQ_START+INTERRUPT_CODEC2)
-+#define FIQ_JPEG (FIQ_START+INTERRUPT_JPEG)
-+#define FIQ_ISP (FIQ_START+INTERRUPT_ISP)
-+#define FIQ_USB (FIQ_START+INTERRUPT_USB)
-+#define FIQ_3D (FIQ_START+INTERRUPT_3D)
-+#define FIQ_TRANSPOSER (FIQ_START+INTERRUPT_TRANSPOSER)
-+#define FIQ_MULTICORESYNC0 (FIQ_START+INTERRUPT_MULTICORESYNC0)
-+#define FIQ_MULTICORESYNC1 (FIQ_START+INTERRUPT_MULTICORESYNC1)
-+#define FIQ_MULTICORESYNC2 (FIQ_START+INTERRUPT_MULTICORESYNC2)
-+#define FIQ_MULTICORESYNC3 (FIQ_START+INTERRUPT_MULTICORESYNC3)
-+#define FIQ_DMA0 (FIQ_START+INTERRUPT_DMA0)
-+#define FIQ_DMA1 (FIQ_START+INTERRUPT_DMA1)
-+#define FIQ_DMA2 (FIQ_START+INTERRUPT_DMA2)
-+#define FIQ_DMA3 (FIQ_START+INTERRUPT_DMA3)
-+#define FIQ_DMA4 (FIQ_START+INTERRUPT_DMA4)
-+#define FIQ_DMA5 (FIQ_START+INTERRUPT_DMA5)
-+#define FIQ_DMA6 (FIQ_START+INTERRUPT_DMA6)
-+#define FIQ_DMA7 (FIQ_START+INTERRUPT_DMA7)
-+#define FIQ_DMA8 (FIQ_START+INTERRUPT_DMA8)
-+#define FIQ_DMA9 (FIQ_START+INTERRUPT_DMA9)
-+#define FIQ_DMA10 (FIQ_START+INTERRUPT_DMA10)
-+#define FIQ_DMA11 (FIQ_START+INTERRUPT_DMA11)
-+#define FIQ_DMA12 (FIQ_START+INTERRUPT_DMA12)
-+#define FIQ_AUX (FIQ_START+INTERRUPT_AUX)
-+#define FIQ_ARM (FIQ_START+INTERRUPT_ARM)
-+#define FIQ_VPUDMA (FIQ_START+INTERRUPT_VPUDMA)
-+#define FIQ_HOSTPORT (FIQ_START+INTERRUPT_HOSTPORT)
-+#define FIQ_VIDEOSCALER (FIQ_START+INTERRUPT_VIDEOSCALER)
-+#define FIQ_CCP2TX (FIQ_START+INTERRUPT_CCP2TX)
-+#define FIQ_SDC (FIQ_START+INTERRUPT_SDC)
-+#define FIQ_DSI0 (FIQ_START+INTERRUPT_DSI0)
-+#define FIQ_AVE (FIQ_START+INTERRUPT_AVE)
-+#define FIQ_CAM0 (FIQ_START+INTERRUPT_CAM0)
-+#define FIQ_CAM1 (FIQ_START+INTERRUPT_CAM1)
-+#define FIQ_HDMI0 (FIQ_START+INTERRUPT_HDMI0)
-+#define FIQ_HDMI1 (FIQ_START+INTERRUPT_HDMI1)
-+#define FIQ_PIXELVALVE1 (FIQ_START+INTERRUPT_PIXELVALVE1)
-+#define FIQ_I2CSPISLV (FIQ_START+INTERRUPT_I2CSPISLV)
-+#define FIQ_DSI1 (FIQ_START+INTERRUPT_DSI1)
-+#define FIQ_PWA0 (FIQ_START+INTERRUPT_PWA0)
-+#define FIQ_PWA1 (FIQ_START+INTERRUPT_PWA1)
-+#define FIQ_CPR (FIQ_START+INTERRUPT_CPR)
-+#define FIQ_SMI (FIQ_START+INTERRUPT_SMI)
-+#define FIQ_GPIO0 (FIQ_START+INTERRUPT_GPIO0)
-+#define FIQ_GPIO1 (FIQ_START+INTERRUPT_GPIO1)
-+#define FIQ_GPIO2 (FIQ_START+INTERRUPT_GPIO2)
-+#define FIQ_GPIO3 (FIQ_START+INTERRUPT_GPIO3)
-+#define FIQ_I2C (FIQ_START+INTERRUPT_I2C)
-+#define FIQ_SPI (FIQ_START+INTERRUPT_SPI)
-+#define FIQ_I2SPCM (FIQ_START+INTERRUPT_I2SPCM)
-+#define FIQ_SDIO (FIQ_START+INTERRUPT_SDIO)
-+#define FIQ_UART (FIQ_START+INTERRUPT_UART)
-+#define FIQ_SLIMBUS (FIQ_START+INTERRUPT_SLIMBUS)
-+#define FIQ_VEC (FIQ_START+INTERRUPT_VEC)
-+#define FIQ_CPG (FIQ_START+INTERRUPT_CPG)
-+#define FIQ_RNG (FIQ_START+INTERRUPT_RNG)
-+#define FIQ_ARASANSDIO (FIQ_START+INTERRUPT_ARASANSDIO)
-+#define FIQ_AVSPMON (FIQ_START+INTERRUPT_AVSPMON)
-+
-+#define FIQ_ARM_TIMER (FIQ_START+INTERRUPT_ARM_TIMER)
-+#define FIQ_ARM_MAILBOX (FIQ_START+INTERRUPT_ARM_MAILBOX)
-+#define FIQ_ARM_DOORBELL_0 (FIQ_START+INTERRUPT_ARM_DOORBELL_0)
-+#define FIQ_ARM_DOORBELL_1 (FIQ_START+INTERRUPT_ARM_DOORBELL_1)
-+#define FIQ_VPU0_HALTED (FIQ_START+INTERRUPT_VPU0_HALTED)
-+#define FIQ_VPU1_HALTED (FIQ_START+INTERRUPT_VPU1_HALTED)
-+#define FIQ_ILLEGAL_TYPE0 (FIQ_START+INTERRUPT_ILLEGAL_TYPE0)
-+#define FIQ_ILLEGAL_TYPE1 (FIQ_START+INTERRUPT_ILLEGAL_TYPE1)
-+#define FIQ_PENDING1 (FIQ_START+INTERRUPT_PENDING1)
-+#define FIQ_PENDING2 (FIQ_START+INTERRUPT_PENDING2)
-+
-+#define GPIO_IRQ_START (HARD_IRQS + FIQ_IRQS)
-+
-+#define HARD_IRQS (64 + 21)
-+#define FIQ_IRQS (64 + 21)
-+#define GPIO_IRQS (32*5)
-+
-+#define NR_IRQS HARD_IRQS+FIQ_IRQS+GPIO_IRQS
-+
-+
-+#endif /* _BCM2708_IRQS_H_ */
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/memory.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/memory.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/memory.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/memory.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,57 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/memory.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ASM_ARCH_MEMORY_H
-+#define __ASM_ARCH_MEMORY_H
-+
-+/* Memory overview:
-+
-+ [ARMcore] <--virtual addr-->
-+ [ARMmmu] <--physical addr-->
-+ [GERTmap] <--bus add-->
-+ [VCperiph]
-+
-+*/
-+
-+/*
-+ * Physical DRAM offset.
-+ */
-+#define PLAT_PHYS_OFFSET UL(0x00000000)
-+#define VC_ARMMEM_OFFSET UL(0x00000000) /* offset in VC of ARM memory */
-+
-+#ifdef CONFIG_BCM2708_NOL2CACHE
-+ #define _REAL_BUS_OFFSET UL(0xC0000000) /* don't use L1 or L2 caches */
-+#else
-+ #define _REAL_BUS_OFFSET UL(0x40000000) /* use L2 cache */
-+#endif
-+
-+/* We're using the memory at 64M in the VideoCore for Linux - this adjustment
-+ * will provide the offset into this area as well as setting the bits that
-+ * stop the L1 and L2 cache from being used
-+ *
-+ * WARNING: this only works because the ARM is given memory at a fixed location
-+ * (ARMMEM_OFFSET)
-+ */
-+#define BUS_OFFSET (VC_ARMMEM_OFFSET + _REAL_BUS_OFFSET)
-+#define __virt_to_bus(x) ((x) + (BUS_OFFSET - PAGE_OFFSET))
-+#define __bus_to_virt(x) ((x) - (BUS_OFFSET - PAGE_OFFSET))
-+#define __pfn_to_bus(x) (__pfn_to_phys(x) + (BUS_OFFSET - PLAT_PHYS_OFFSET))
-+#define __bus_to_pfn(x) __phys_to_pfn((x) - (BUS_OFFSET - PLAT_PHYS_OFFSET))
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/platform.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/platform.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/platform.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/platform.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,226 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/platform.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef _BCM2708_PLATFORM_H
-+#define _BCM2708_PLATFORM_H
-+
-+
-+/* macros to get at IO space when running virtually */
-+#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
-+
-+#define __io_address(n) IOMEM(IO_ADDRESS(n))
-+
-+
-+/*
-+ * SDRAM
-+ */
-+#define BCM2708_SDRAM_BASE 0x00000000
-+
-+/*
-+ * Logic expansion modules
-+ *
-+ */
-+
-+
-+/* ------------------------------------------------------------------------
-+ * BCM2708 ARMCTRL Registers
-+ * ------------------------------------------------------------------------
-+ */
-+
-+#define HW_REGISTER_RW(addr) (addr)
-+#define HW_REGISTER_RO(addr) (addr)
-+
-+#include "arm_control.h"
-+#undef ARM_BASE
-+
-+/*
-+ * Definitions and addresses for the ARM CONTROL logic
-+ * This file is manually generated.
-+ */
-+
-+#define BCM2708_PERI_BASE 0x20000000
-+#define IC0_BASE (BCM2708_PERI_BASE + 0x2000)
-+#define ST_BASE (BCM2708_PERI_BASE + 0x3000) /* System Timer */
-+#define MPHI_BASE (BCM2708_PERI_BASE + 0x6000) /* Message -based Parallel Host Interface */
-+#define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */
-+#define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */
-+#define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
-+#define RNG_BASE (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
-+#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */
-+#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
-+#define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
-+#define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
-+#define BSC0_BASE (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
-+#define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
-+#define EMMC_BASE (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
-+#define SMI_BASE (BCM2708_PERI_BASE + 0x600000) /* SMI */
-+#define BSC1_BASE (BCM2708_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */
-+#define USB_BASE (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
-+#define MCORE_BASE (BCM2708_PERI_BASE + 0x0000) /* Fake frame buffer device (actually the multicore sync block*/
-+
-+#define ARMCTRL_BASE (ARM_BASE + 0x000)
-+#define ARMCTRL_IC_BASE (ARM_BASE + 0x200) /* ARM interrupt controller */
-+#define ARMCTRL_TIMER0_1_BASE (ARM_BASE + 0x400) /* Timer 0 and 1 */
-+#define ARMCTRL_0_SBM_BASE (ARM_BASE + 0x800) /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
-+
-+
-+/*
-+ * Interrupt assignments
-+ */
-+
-+#define ARM_IRQ1_BASE 0
-+#define INTERRUPT_TIMER0 (ARM_IRQ1_BASE + 0)
-+#define INTERRUPT_TIMER1 (ARM_IRQ1_BASE + 1)
-+#define INTERRUPT_TIMER2 (ARM_IRQ1_BASE + 2)
-+#define INTERRUPT_TIMER3 (ARM_IRQ1_BASE + 3)
-+#define INTERRUPT_CODEC0 (ARM_IRQ1_BASE + 4)
-+#define INTERRUPT_CODEC1 (ARM_IRQ1_BASE + 5)
-+#define INTERRUPT_CODEC2 (ARM_IRQ1_BASE + 6)
-+#define INTERRUPT_VC_JPEG (ARM_IRQ1_BASE + 7)
-+#define INTERRUPT_ISP (ARM_IRQ1_BASE + 8)
-+#define INTERRUPT_VC_USB (ARM_IRQ1_BASE + 9)
-+#define INTERRUPT_VC_3D (ARM_IRQ1_BASE + 10)
-+#define INTERRUPT_TRANSPOSER (ARM_IRQ1_BASE + 11)
-+#define INTERRUPT_MULTICORESYNC0 (ARM_IRQ1_BASE + 12)
-+#define INTERRUPT_MULTICORESYNC1 (ARM_IRQ1_BASE + 13)
-+#define INTERRUPT_MULTICORESYNC2 (ARM_IRQ1_BASE + 14)
-+#define INTERRUPT_MULTICORESYNC3 (ARM_IRQ1_BASE + 15)
-+#define INTERRUPT_DMA0 (ARM_IRQ1_BASE + 16)
-+#define INTERRUPT_DMA1 (ARM_IRQ1_BASE + 17)
-+#define INTERRUPT_VC_DMA2 (ARM_IRQ1_BASE + 18)
-+#define INTERRUPT_VC_DMA3 (ARM_IRQ1_BASE + 19)
-+#define INTERRUPT_DMA4 (ARM_IRQ1_BASE + 20)
-+#define INTERRUPT_DMA5 (ARM_IRQ1_BASE + 21)
-+#define INTERRUPT_DMA6 (ARM_IRQ1_BASE + 22)
-+#define INTERRUPT_DMA7 (ARM_IRQ1_BASE + 23)
-+#define INTERRUPT_DMA8 (ARM_IRQ1_BASE + 24)
-+#define INTERRUPT_DMA9 (ARM_IRQ1_BASE + 25)
-+#define INTERRUPT_DMA10 (ARM_IRQ1_BASE + 26)
-+#define INTERRUPT_DMA11 (ARM_IRQ1_BASE + 27)
-+#define INTERRUPT_DMA12 (ARM_IRQ1_BASE + 28)
-+#define INTERRUPT_AUX (ARM_IRQ1_BASE + 29)
-+#define INTERRUPT_ARM (ARM_IRQ1_BASE + 30)
-+#define INTERRUPT_VPUDMA (ARM_IRQ1_BASE + 31)
-+
-+#define ARM_IRQ2_BASE 32
-+#define INTERRUPT_HOSTPORT (ARM_IRQ2_BASE + 0)
-+#define INTERRUPT_VIDEOSCALER (ARM_IRQ2_BASE + 1)
-+#define INTERRUPT_CCP2TX (ARM_IRQ2_BASE + 2)
-+#define INTERRUPT_SDC (ARM_IRQ2_BASE + 3)
-+#define INTERRUPT_DSI0 (ARM_IRQ2_BASE + 4)
-+#define INTERRUPT_AVE (ARM_IRQ2_BASE + 5)
-+#define INTERRUPT_CAM0 (ARM_IRQ2_BASE + 6)
-+#define INTERRUPT_CAM1 (ARM_IRQ2_BASE + 7)
-+#define INTERRUPT_HDMI0 (ARM_IRQ2_BASE + 8)
-+#define INTERRUPT_HDMI1 (ARM_IRQ2_BASE + 9)
-+#define INTERRUPT_PIXELVALVE1 (ARM_IRQ2_BASE + 10)
-+#define INTERRUPT_I2CSPISLV (ARM_IRQ2_BASE + 11)
-+#define INTERRUPT_DSI1 (ARM_IRQ2_BASE + 12)
-+#define INTERRUPT_PWA0 (ARM_IRQ2_BASE + 13)
-+#define INTERRUPT_PWA1 (ARM_IRQ2_BASE + 14)
-+#define INTERRUPT_CPR (ARM_IRQ2_BASE + 15)
-+#define INTERRUPT_SMI (ARM_IRQ2_BASE + 16)
-+#define INTERRUPT_GPIO0 (ARM_IRQ2_BASE + 17)
-+#define INTERRUPT_GPIO1 (ARM_IRQ2_BASE + 18)
-+#define INTERRUPT_GPIO2 (ARM_IRQ2_BASE + 19)
-+#define INTERRUPT_GPIO3 (ARM_IRQ2_BASE + 20)
-+#define INTERRUPT_VC_I2C (ARM_IRQ2_BASE + 21)
-+#define INTERRUPT_VC_SPI (ARM_IRQ2_BASE + 22)
-+#define INTERRUPT_VC_I2SPCM (ARM_IRQ2_BASE + 23)
-+#define INTERRUPT_VC_SDIO (ARM_IRQ2_BASE + 24)
-+#define INTERRUPT_VC_UART (ARM_IRQ2_BASE + 25)
-+#define INTERRUPT_SLIMBUS (ARM_IRQ2_BASE + 26)
-+#define INTERRUPT_VEC (ARM_IRQ2_BASE + 27)
-+#define INTERRUPT_CPG (ARM_IRQ2_BASE + 28)
-+#define INTERRUPT_RNG (ARM_IRQ2_BASE + 29)
-+#define INTERRUPT_VC_ARASANSDIO (ARM_IRQ2_BASE + 30)
-+#define INTERRUPT_AVSPMON (ARM_IRQ2_BASE + 31)
-+
-+#define ARM_IRQ0_BASE 64
-+#define INTERRUPT_ARM_TIMER (ARM_IRQ0_BASE + 0)
-+#define INTERRUPT_ARM_MAILBOX (ARM_IRQ0_BASE + 1)
-+#define INTERRUPT_ARM_DOORBELL_0 (ARM_IRQ0_BASE + 2)
-+#define INTERRUPT_ARM_DOORBELL_1 (ARM_IRQ0_BASE + 3)
-+#define INTERRUPT_VPU0_HALTED (ARM_IRQ0_BASE + 4)
-+#define INTERRUPT_VPU1_HALTED (ARM_IRQ0_BASE + 5)
-+#define INTERRUPT_ILLEGAL_TYPE0 (ARM_IRQ0_BASE + 6)
-+#define INTERRUPT_ILLEGAL_TYPE1 (ARM_IRQ0_BASE + 7)
-+#define INTERRUPT_PENDING1 (ARM_IRQ0_BASE + 8)
-+#define INTERRUPT_PENDING2 (ARM_IRQ0_BASE + 9)
-+#define INTERRUPT_JPEG (ARM_IRQ0_BASE + 10)
-+#define INTERRUPT_USB (ARM_IRQ0_BASE + 11)
-+#define INTERRUPT_3D (ARM_IRQ0_BASE + 12)
-+#define INTERRUPT_DMA2 (ARM_IRQ0_BASE + 13)
-+#define INTERRUPT_DMA3 (ARM_IRQ0_BASE + 14)
-+#define INTERRUPT_I2C (ARM_IRQ0_BASE + 15)
-+#define INTERRUPT_SPI (ARM_IRQ0_BASE + 16)
-+#define INTERRUPT_I2SPCM (ARM_IRQ0_BASE + 17)
-+#define INTERRUPT_SDIO (ARM_IRQ0_BASE + 18)
-+#define INTERRUPT_UART (ARM_IRQ0_BASE + 19)
-+#define INTERRUPT_ARASANSDIO (ARM_IRQ0_BASE + 20)
-+
-+#define MAXIRQNUM (32 + 32 + 20)
-+#define MAXFIQNUM (32 + 32 + 20)
-+
-+#define MAX_TIMER 2
-+#define MAX_PERIOD 699050
-+#define TICKS_PER_uSEC 1
-+
-+/*
-+ * These are useconds NOT ticks.
-+ *
-+ */
-+#define mSEC_1 1000
-+#define mSEC_5 (mSEC_1 * 5)
-+#define mSEC_10 (mSEC_1 * 10)
-+#define mSEC_25 (mSEC_1 * 25)
-+#define SEC_1 (mSEC_1 * 1000)
-+
-+/*
-+ * Watchdog
-+ */
-+#define PM_RSTC (PM_BASE+0x1c)
-+#define PM_RSTS (PM_BASE+0x20)
-+#define PM_WDOG (PM_BASE+0x24)
-+
-+#define PM_WDOG_RESET 0000000000
-+#define PM_PASSWORD 0x5a000000
-+#define PM_WDOG_TIME_SET 0x000fffff
-+#define PM_RSTC_WRCFG_CLR 0xffffffcf
-+#define PM_RSTC_WRCFG_SET 0x00000030
-+#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
-+#define PM_RSTC_RESET 0x00000102
-+
-+#define PM_RSTS_HADPOR_SET 0x00001000
-+#define PM_RSTS_HADSRH_SET 0x00000400
-+#define PM_RSTS_HADSRF_SET 0x00000200
-+#define PM_RSTS_HADSRQ_SET 0x00000100
-+#define PM_RSTS_HADWRH_SET 0x00000040
-+#define PM_RSTS_HADWRF_SET 0x00000020
-+#define PM_RSTS_HADWRQ_SET 0x00000010
-+#define PM_RSTS_HADDRH_SET 0x00000004
-+#define PM_RSTS_HADDRF_SET 0x00000002
-+#define PM_RSTS_HADDRQ_SET 0x00000001
-+
-+#define UART0_CLOCK 3000000
-+
-+#endif
-+
-+/* END */
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/power.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/power.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/power.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/power.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,26 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/power.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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 device provides a shared mechanism for controlling the power to
-+ * VideoCore subsystems.
-+ */
-+
-+#ifndef _MACH_BCM2708_POWER_H
-+#define _MACH_BCM2708_POWER_H
-+
-+#include <linux/types.h>
-+#include <mach/arm_power.h>
-+
-+typedef unsigned int BCM_POWER_HANDLE_T;
-+
-+extern int bcm_power_open(BCM_POWER_HANDLE_T *handle);
-+extern int bcm_power_request(BCM_POWER_HANDLE_T handle, uint32_t request);
-+extern int bcm_power_close(BCM_POWER_HANDLE_T handle);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/system.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/system.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/system.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/system.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,38 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/system.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ * Copyright (C) 2003 ARM Limited
-+ * Copyright (C) 2000 Deep Blue Solutions Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ASM_ARCH_SYSTEM_H
-+#define __ASM_ARCH_SYSTEM_H
-+
-+#include <linux/io.h>
-+#include <mach/hardware.h>
-+#include <mach/platform.h>
-+
-+static inline void arch_idle(void)
-+{
-+ /*
-+ * This should do all the clock switching
-+ * and wait for interrupt tricks
-+ */
-+ cpu_do_idle();
-+}
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/timex.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/timex.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/timex.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/timex.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,23 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/timex.h
-+ *
-+ * BCM2708 sysem clock frequency
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#define CLOCK_TICK_RATE (1000000)
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/uncompress.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/uncompress.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/uncompress.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/uncompress.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,84 @@
-+/*
-+ * arch/arm/mach-bcn2708/include/mach/uncompress.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ * Copyright (C) 2003 ARM Limited
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/amba/serial.h>
-+#include <mach/hardware.h>
-+
-+#define UART_BAUD 115200
-+
-+#define BCM2708_UART_DR __io(UART0_BASE + UART01x_DR)
-+#define BCM2708_UART_FR __io(UART0_BASE + UART01x_FR)
-+#define BCM2708_UART_IBRD __io(UART0_BASE + UART011_IBRD)
-+#define BCM2708_UART_FBRD __io(UART0_BASE + UART011_FBRD)
-+#define BCM2708_UART_LCRH __io(UART0_BASE + UART011_LCRH)
-+#define BCM2708_UART_CR __io(UART0_BASE + UART011_CR)
-+
-+/*
-+ * This does not append a newline
-+ */
-+static inline void putc(int c)
-+{
-+ while (__raw_readl(BCM2708_UART_FR) & UART01x_FR_TXFF)
-+ barrier();
-+
-+ __raw_writel(c, BCM2708_UART_DR);
-+}
-+
-+static inline void flush(void)
-+{
-+ int fr;
-+
-+ do {
-+ fr = __raw_readl(BCM2708_UART_FR);
-+ barrier();
-+ } while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
-+}
-+
-+static inline void arch_decomp_setup(void)
-+{
-+ int temp, div, rem, frac;
-+
-+ temp = 16 * UART_BAUD;
-+ div = UART0_CLOCK / temp;
-+ rem = UART0_CLOCK % temp;
-+ temp = (8 * rem) / UART_BAUD;
-+ frac = (temp >> 1) + (temp & 1);
-+
-+ /* Make sure the UART is disabled before we start */
-+ __raw_writel(0, BCM2708_UART_CR);
-+
-+ /* Set the baud rate */
-+ __raw_writel(div, BCM2708_UART_IBRD);
-+ __raw_writel(frac, BCM2708_UART_FBRD);
-+
-+ /* Set the UART to 8n1, FIFO enabled */
-+ __raw_writel(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, BCM2708_UART_LCRH);
-+
-+ /* Enable the UART */
-+ __raw_writel(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,
-+ BCM2708_UART_CR);
-+}
-+
-+/*
-+ * nothing to do
-+ */
-+#define arch_decomp_wdog()
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vcio.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vcio.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vcio.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vcio.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,141 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/vcio.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef _MACH_BCM2708_VCIO_H
-+#define _MACH_BCM2708_VCIO_H
-+
-+/* Routines to handle I/O via the VideoCore "ARM control" registers
-+ * (semaphores, doorbells, mailboxes)
-+ */
-+
-+#define BCM_VCIO_DRIVER_NAME "bcm2708_vcio"
-+
-+/* Constants shared with the ARM identifying separate mailbox channels */
-+#define MBOX_CHAN_POWER 0 /* for use by the power management interface */
-+#define MBOX_CHAN_FB 1 /* for use by the frame buffer */
-+#define MBOX_CHAN_VCHIQ 3 /* for use by the VCHIQ interface */
-+#define MBOX_CHAN_PROPERTY 8 /* for use by the property channel */
-+#define MBOX_CHAN_COUNT 9
-+
-+/* Mailbox property tags */
-+enum {
-+ VCMSG_PROPERTY_END = 0x00000000,
-+ VCMSG_GET_FIRMWARE_REVISION = 0x00000001,
-+ VCMSG_GET_BOARD_MODEL = 0x00010001,
-+ VCMSG_GET_BOARD_REVISION = 0x00020002,
-+ VCMSG_GET_BOARD_MAC_ADDRESS = 0x00020003,
-+ VCMSG_GET_BOARD_SERIAL = 0x00020004,
-+ VCMSG_GET_ARM_MEMORY = 0x00020005,
-+ VCMSG_GET_VC_MEMORY = 0x00020006,
-+ VCMSG_GET_CLOCKS = 0x00020007,
-+ VCMSG_GET_COMMAND_LINE = 0x00050001,
-+ VCMSG_GET_DMA_CHANNELS = 0x00060001,
-+ VCMSG_GET_POWER_STATE = 0x00020001,
-+ VCMSG_GET_TIMING = 0x00020002,
-+ VCMSG_SET_POWER_STATE = 0x00028001,
-+ VCMSG_GET_CLOCK_STATE = 0x00030001,
-+ VCMSG_SET_CLOCK_STATE = 0x00038001,
-+ VCMSG_GET_CLOCK_RATE = 0x00030002,
-+ VCMSG_SET_CLOCK_RATE = 0x00038002,
-+ VCMSG_GET_VOLTAGE = 0x00030003,
-+ VCMSG_SET_VOLTAGE = 0x00038003,
-+ VCMSG_GET_MAX_CLOCK = 0x00030004,
-+ VCMSG_GET_MAX_VOLTAGE = 0x00030005,
-+ VCMSG_GET_TEMPERATURE = 0x00030006,
-+ VCMSG_GET_MIN_CLOCK = 0x00030007,
-+ VCMSG_GET_MIN_VOLTAGE = 0x00030008,
-+ VCMSG_GET_TURBO = 0x00030009,
-+ VCMSG_SET_TURBO = 0x00038009,
-+ VCMSG_SET_ALLOCATE_BUFFER = 0x00040001,
-+ VCMSG_SET_RELEASE_BUFFER = 0x00048001,
-+ VCMSG_SET_BLANK_SCREEN = 0x00040002,
-+ VCMSG_TST_BLANK_SCREEN = 0x00044002,
-+ VCMSG_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
-+ VCMSG_TST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
-+ VCMSG_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
-+ VCMSG_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
-+ VCMSG_TST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
-+ VCMSG_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
-+ VCMSG_GET_DEPTH = 0x00040005,
-+ VCMSG_TST_DEPTH = 0x00044005,
-+ VCMSG_SET_DEPTH = 0x00048005,
-+ VCMSG_GET_PIXEL_ORDER = 0x00040006,
-+ VCMSG_TST_PIXEL_ORDER = 0x00044006,
-+ VCMSG_SET_PIXEL_ORDER = 0x00048006,
-+ VCMSG_GET_ALPHA_MODE = 0x00040007,
-+ VCMSG_TST_ALPHA_MODE = 0x00044007,
-+ VCMSG_SET_ALPHA_MODE = 0x00048007,
-+ VCMSG_GET_PITCH = 0x00040008,
-+ VCMSG_TST_PITCH = 0x00044008,
-+ VCMSG_SET_PITCH = 0x00048008,
-+ VCMSG_GET_VIRTUAL_OFFSET = 0x00040009,
-+ VCMSG_TST_VIRTUAL_OFFSET = 0x00044009,
-+ VCMSG_SET_VIRTUAL_OFFSET = 0x00048009,
-+ VCMSG_GET_OVERSCAN = 0x0004000a,
-+ VCMSG_TST_OVERSCAN = 0x0004400a,
-+ VCMSG_SET_OVERSCAN = 0x0004800a,
-+ VCMSG_GET_PALETTE = 0x0004000b,
-+ VCMSG_TST_PALETTE = 0x0004400b,
-+ VCMSG_SET_PALETTE = 0x0004800b,
-+ VCMSG_GET_LAYER = 0x0004000c,
-+ VCMSG_TST_LAYER = 0x0004400c,
-+ VCMSG_SET_LAYER = 0x0004800c,
-+ VCMSG_GET_TRANSFORM = 0x0004000d,
-+ VCMSG_TST_TRANSFORM = 0x0004400d,
-+ VCMSG_SET_TRANSFORM = 0x0004800d,
-+};
-+
-+extern int /*rc*/ bcm_mailbox_read(unsigned chan, uint32_t *data28);
-+extern int /*rc*/ bcm_mailbox_write(unsigned chan, uint32_t data28);
-+extern int /*rc*/ bcm_mailbox_property(void *data, int size);
-+
-+#include <linux/ioctl.h>
-+
-+/*
-+ * The major device number. We can't rely on dynamic
-+ * registration any more, because ioctls need to know
-+ * it.
-+ */
-+#define MAJOR_NUM 100
-+
-+/*
-+ * Set the message of the device driver
-+ */
-+#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
-+/*
-+ * _IOWR means that we're creating an ioctl command
-+ * number for passing information from a user process
-+ * to the kernel module and from the kernel module to user process
-+ *
-+ * The first arguments, MAJOR_NUM, is the major device
-+ * number we're using.
-+ *
-+ * The second argument is the number of the command
-+ * (there could be several with different meanings).
-+ *
-+ * The third argument is the type we want to get from
-+ * the process to the kernel.
-+ */
-+
-+/*
-+ * The name of the device file
-+ */
-+#define DEVICE_FILE_NAME "char_dev"
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vc_mem.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vc_mem.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vc_mem.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vc_mem.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,35 @@
-+/*****************************************************************************
-+* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#if !defined( VC_MEM_H )
-+#define VC_MEM_H
-+
-+#include <linux/ioctl.h>
-+
-+#define VC_MEM_IOC_MAGIC 'v'
-+
-+#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
-+#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
-+#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
-+#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
-+
-+#if defined( __KERNEL__ )
-+#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
-+
-+extern unsigned long mm_vc_mem_phys_addr;
-+extern unsigned int mm_vc_mem_size;
-+extern int vc_mem_get_current_size( void );
-+#endif
-+
-+#endif /* VC_MEM_H */
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vc_support.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vc_support.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vc_support.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vc_support.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,69 @@
-+#ifndef _VC_SUPPORT_H_
-+#define _VC_SUPPORT_H_
-+
-+/*
-+ * vc_support.h
-+ *
-+ * Created on: 25 Nov 2012
-+ * Author: Simon
-+ */
-+
-+enum {
-+/*
-+ If a MEM_HANDLE_T is discardable, the memory manager may resize it to size
-+ 0 at any time when it is not locked or retained.
-+ */
-+ MEM_FLAG_DISCARDABLE = 1 << 0,
-+
-+ /*
-+ If a MEM_HANDLE_T is allocating (or normal), its block of memory will be
-+ accessed in an allocating fashion through the cache.
-+ */
-+ MEM_FLAG_NORMAL = 0 << 2,
-+ MEM_FLAG_ALLOCATING = MEM_FLAG_NORMAL,
-+
-+ /*
-+ If a MEM_HANDLE_T is direct, its block of memory will be accessed
-+ directly, bypassing the cache.
-+ */
-+ MEM_FLAG_DIRECT = 1 << 2,
-+
-+ /*
-+ If a MEM_HANDLE_T is coherent, its block of memory will be accessed in a
-+ non-allocating fashion through the cache.
-+ */
-+ MEM_FLAG_COHERENT = 2 << 2,
-+
-+ /*
-+ If a MEM_HANDLE_T is L1-nonallocating, its block of memory will be accessed by
-+ the VPU in a fashion which is allocating in L2, but only coherent in L1.
-+ */
-+ MEM_FLAG_L1_NONALLOCATING = (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT),
-+
-+ /*
-+ If a MEM_HANDLE_T is zero'd, its contents are set to 0 rather than
-+ MEM_HANDLE_INVALID on allocation and resize up.
-+ */
-+ MEM_FLAG_ZERO = 1 << 4,
-+
-+ /*
-+ If a MEM_HANDLE_T is uninitialised, it will not be reset to a defined value
-+ (either zero, or all 1's) on allocation.
-+ */
-+ MEM_FLAG_NO_INIT = 1 << 5,
-+
-+ /*
-+ Hints.
-+ */
-+ MEM_FLAG_HINT_PERMALOCK = 1 << 6, /* Likely to be locked for long periods of time. */
-+};
-+
-+unsigned int AllocateVcMemory(unsigned int *pHandle, unsigned int size, unsigned int alignment, unsigned int flags);
-+unsigned int ReleaseVcMemory(unsigned int handle);
-+unsigned int LockVcMemory(unsigned int *pBusAddress, unsigned int handle);
-+unsigned int UnlockVcMemory(unsigned int handle);
-+
-+unsigned int ExecuteVcCode(unsigned int code,
-+ unsigned int r0, unsigned int r1, unsigned int r2, unsigned int r3, unsigned int r4, unsigned int r5);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vmalloc.h linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vmalloc.h
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/include/mach/vmalloc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/include/mach/vmalloc.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,20 @@
-+/*
-+ * arch/arm/mach-bcm2708/include/mach/vmalloc.h
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#define VMALLOC_END (0xe8000000)
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/Kconfig linux-3.11.10/arch/arm/mach-bcm2708/Kconfig
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,48 @@
-+menu "Broadcom BCM2708 Implementations"
-+ depends on ARCH_BCM2708
-+
-+config MACH_BCM2708
-+ bool "Broadcom BCM2708 Development Platform"
-+ select NEED_MACH_MEMORY_H
-+ select NEED_MACH_IO_H
-+ select CPU_V6
-+ help
-+ Include support for the Broadcom(R) BCM2708 platform.
-+
-+config BCM2708_GPIO
-+ bool "BCM2708 gpio support"
-+ depends on MACH_BCM2708
-+ select ARCH_REQUIRE_GPIOLIB
-+ default y
-+ help
-+ Include support for the Broadcom(R) BCM2708 gpio.
-+
-+config BCM2708_VCMEM
-+ bool "Videocore Memory"
-+ depends on MACH_BCM2708
-+ default y
-+ help
-+ Helper for videocore memory access and total size allocation.
-+
-+config BCM2708_NOL2CACHE
-+ bool "Videocore L2 cache disable"
-+ depends on MACH_BCM2708
-+ default n
-+ help
-+ Do not allow ARM to use GPU's L2 cache. Requires disable_l2cache in config.txt.
-+
-+config BCM2708_DMAER
-+ tristate "BCM2708 DMA helper"
-+ depends on MACH_BCM2708
-+ default n
-+ help
-+ Enable DMA helper for accelerating X composition
-+
-+config BCM2708_SPIDEV
-+ bool "Bind spidev to SPI0 master"
-+ depends on MACH_BCM2708
-+ depends on SPI
-+ default y
-+ help
-+ Binds spidev driver to the SPI0 master
-+endmenu
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/Makefile linux-3.11.10/arch/arm/mach-bcm2708/Makefile
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the linux kernel.
-+#
-+
-+obj-$(CONFIG_MACH_BCM2708) += clock.o bcm2708.o armctrl.o vcio.o power.o dma.o
-+obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o
-+obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
-+
-+obj-$(CONFIG_BCM2708_DMAER) += dmaer_master.o
-+dmaer_master-objs := dmaer.o vc_support.o
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/Makefile.boot linux-3.11.10/arch/arm/mach-bcm2708/Makefile.boot
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/Makefile.boot 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/Makefile.boot 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,3 @@
-+ zreladdr-y := 0x00008000
-+params_phys-y := 0x00000100
-+initrd_phys-y := 0x00800000
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/power.c linux-3.11.10/arch/arm/mach-bcm2708/power.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/power.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/power.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,194 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/power.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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 device provides a shared mechanism for controlling the power to
-+ * VideoCore subsystems.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/semaphore.h>
-+#include <linux/bug.h>
-+#include <mach/power.h>
-+#include <mach/vcio.h>
-+#include <mach/arm_power.h>
-+
-+#define DRIVER_NAME "bcm2708_power"
-+
-+#define BCM_POWER_MAXCLIENTS 4
-+#define BCM_POWER_NOCLIENT (1<<31)
-+
-+/* Some drivers expect there devices to be permanently powered */
-+#define BCM_POWER_ALWAYS_ON (BCM_POWER_USB)
-+
-+#if 1
-+#define DPRINTK printk
-+#else
-+#define DPRINTK if (0) printk
-+#endif
-+
-+struct state_struct {
-+ uint32_t global_request;
-+ uint32_t client_request[BCM_POWER_MAXCLIENTS];
-+ struct semaphore client_mutex;
-+ struct semaphore mutex;
-+} g_state;
-+
-+int bcm_power_open(BCM_POWER_HANDLE_T *handle)
-+{
-+ BCM_POWER_HANDLE_T i;
-+ int ret = -EBUSY;
-+
-+ down(&g_state.client_mutex);
-+
-+ for (i = 0; i < BCM_POWER_MAXCLIENTS; i++) {
-+ if (g_state.client_request[i] == BCM_POWER_NOCLIENT) {
-+ g_state.client_request[i] = BCM_POWER_NONE;
-+ *handle = i;
-+ ret = 0;
-+ break;
-+ }
-+ }
-+
-+ up(&g_state.client_mutex);
-+
-+ DPRINTK("bcm_power_open() -> %d\n", *handle);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(bcm_power_open);
-+
-+int bcm_power_request(BCM_POWER_HANDLE_T handle, uint32_t request)
-+{
-+ int rc = 0;
-+
-+ DPRINTK("bcm_power_request(%d, %x)\n", handle, request);
-+
-+ if ((handle < BCM_POWER_MAXCLIENTS) &&
-+ (g_state.client_request[handle] != BCM_POWER_NOCLIENT)) {
-+ if (down_interruptible(&g_state.mutex) != 0) {
-+ DPRINTK("bcm_power_request -> interrupted\n");
-+ return -EINTR;
-+ }
-+
-+ if (request != g_state.client_request[handle]) {
-+ uint32_t others_request = 0;
-+ uint32_t global_request;
-+ BCM_POWER_HANDLE_T i;
-+
-+ for (i = 0; i < BCM_POWER_MAXCLIENTS; i++) {
-+ if (i != handle)
-+ others_request |=
-+ g_state.client_request[i];
-+ }
-+ others_request &= ~BCM_POWER_NOCLIENT;
-+
-+ global_request = request | others_request;
-+ if (global_request != g_state.global_request) {
-+ uint32_t actual;
-+
-+ /* Send a request to VideoCore */
-+ bcm_mailbox_write(MBOX_CHAN_POWER,
-+ global_request << 4);
-+
-+ /* Wait for a response during power-up */
-+ if (global_request & ~g_state.global_request) {
-+ rc = bcm_mailbox_read(MBOX_CHAN_POWER,
-+ &actual);
-+ DPRINTK
-+ ("bcm_mailbox_read -> %08x, %d\n",
-+ actual, rc);
-+ actual >>= 4;
-+ } else {
-+ rc = 0;
-+ actual = global_request;
-+ }
-+
-+ if (rc == 0) {
-+ if (actual != global_request) {
-+ printk(KERN_ERR
-+ "%s: prev global %x, new global %x, actual %x, request %x, others_request %x\n",
-+ __func__,
-+ g_state.global_request,
-+ global_request, actual, request, others_request);
-+ /* A failure */
-+ BUG_ON((others_request & actual)
-+ != others_request);
-+ request &= actual;
-+ rc = -EIO;
-+ }
-+
-+ g_state.global_request = actual;
-+ g_state.client_request[handle] =
-+ request;
-+ }
-+ }
-+ }
-+ up(&g_state.mutex);
-+ } else {
-+ rc = -EINVAL;
-+ }
-+ DPRINTK("bcm_power_request -> %d\n", rc);
-+ return rc;
-+}
-+EXPORT_SYMBOL_GPL(bcm_power_request);
-+
-+int bcm_power_close(BCM_POWER_HANDLE_T handle)
-+{
-+ int rc;
-+
-+ DPRINTK("bcm_power_close(%d)\n", handle);
-+
-+ rc = bcm_power_request(handle, BCM_POWER_NONE);
-+ if (rc == 0)
-+ g_state.client_request[handle] = BCM_POWER_NOCLIENT;
-+
-+ return rc;
-+}
-+EXPORT_SYMBOL_GPL(bcm_power_close);
-+
-+static int __init bcm_power_init(void)
-+{
-+#if defined(BCM_POWER_ALWAYS_ON)
-+ BCM_POWER_HANDLE_T always_on_handle;
-+#endif
-+ int rc = 0;
-+ int i;
-+
-+ printk(KERN_INFO "bcm_power: Broadcom power driver\n");
-+ bcm_mailbox_write(MBOX_CHAN_POWER, 0);
-+
-+ for (i = 0; i < BCM_POWER_MAXCLIENTS; i++)
-+ g_state.client_request[i] = BCM_POWER_NOCLIENT;
-+
-+ sema_init(&g_state.client_mutex, 1);
-+ sema_init(&g_state.mutex, 1);
-+
-+ g_state.global_request = 0;
-+
-+#if defined(BCM_POWER_ALWAYS_ON)
-+ if (BCM_POWER_ALWAYS_ON) {
-+ bcm_power_open(&always_on_handle);
-+ bcm_power_request(always_on_handle, BCM_POWER_ALWAYS_ON);
-+ }
-+#endif
-+
-+ return rc;
-+}
-+
-+static void __exit bcm_power_exit(void)
-+{
-+ bcm_mailbox_write(MBOX_CHAN_POWER, 0);
-+}
-+
-+arch_initcall(bcm_power_init); /* Initialize early */
-+module_exit(bcm_power_exit);
-+
-+MODULE_AUTHOR("Phil Elwell");
-+MODULE_DESCRIPTION("Interface to BCM2708 power management");
-+MODULE_LICENSE("GPL");
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/vcio.c linux-3.11.10/arch/arm/mach-bcm2708/vcio.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/vcio.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/vcio.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,474 @@
-+/*
-+ * linux/arch/arm/mach-bcm2708/vcio.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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 device provides a shared mechanism for writing to the mailboxes,
-+ * semaphores, doorbells etc. that are shared between the ARM and the
-+ * VideoCore processor
-+ */
-+
-+#if defined(CONFIG_SERIAL_BCM_MBOX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-+#define SUPPORT_SYSRQ
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/console.h>
-+#include <linux/serial_core.h>
-+#include <linux/serial.h>
-+#include <linux/errno.h>
-+#include <linux/device.h>
-+#include <linux/init.h>
-+#include <linux/mm.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/platform_device.h>
-+#include <linux/sysrq.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+
-+#include <linux/io.h>
-+
-+#include <mach/vcio.h>
-+#include <mach/platform.h>
-+
-+#include <asm/uaccess.h>
-+
-+
-+#define DRIVER_NAME BCM_VCIO_DRIVER_NAME
-+
-+/* ----------------------------------------------------------------------
-+ * Mailbox
-+ * -------------------------------------------------------------------- */
-+
-+/* offsets from a mail box base address */
-+#define MAIL_WRT 0x00 /* write - and next 4 words */
-+#define MAIL_RD 0x00 /* read - and next 4 words */
-+#define MAIL_POL 0x10 /* read without popping the fifo */
-+#define MAIL_SND 0x14 /* sender ID (bottom two bits) */
-+#define MAIL_STA 0x18 /* status */
-+#define MAIL_CNF 0x1C /* configuration */
-+
-+#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
-+#define MBOX_MSG_LSB(chan, data28) (((data28) << 4) | ((chan) & 0xf))
-+#define MBOX_CHAN(msg) ((msg) & 0xf)
-+#define MBOX_DATA28(msg) ((msg) & ~0xf)
-+#define MBOX_DATA28_LSB(msg) (((uint32_t)msg) >> 4)
-+
-+#define MBOX_MAGIC 0xd0d0c0de
-+
-+struct vc_mailbox {
-+ struct device *dev; /* parent device */
-+ void __iomem *status;
-+ void __iomem *config;
-+ void __iomem *read;
-+ void __iomem *write;
-+ uint32_t msg[MBOX_CHAN_COUNT];
-+ struct semaphore sema[MBOX_CHAN_COUNT];
-+ uint32_t magic;
-+};
-+
-+static void mbox_init(struct vc_mailbox *mbox_out, struct device *dev,
-+ uint32_t addr_mbox)
-+{
-+ int i;
-+
-+ mbox_out->dev = dev;
-+ mbox_out->status = __io_address(addr_mbox + MAIL_STA);
-+ mbox_out->config = __io_address(addr_mbox + MAIL_CNF);
-+ mbox_out->read = __io_address(addr_mbox + MAIL_RD);
-+ /* Write to the other mailbox */
-+ mbox_out->write =
-+ __io_address((addr_mbox ^ ARM_0_MAIL0_WRT ^ ARM_0_MAIL1_WRT) +
-+ MAIL_WRT);
-+
-+ for (i = 0; i < MBOX_CHAN_COUNT; i++) {
-+ mbox_out->msg[i] = 0;
-+ sema_init(&mbox_out->sema[i], 0);
-+ }
-+
-+ /* Enable the interrupt on data reception */
-+ writel(ARM_MC_IHAVEDATAIRQEN, mbox_out->config);
-+
-+ mbox_out->magic = MBOX_MAGIC;
-+}
-+
-+static int mbox_write(struct vc_mailbox *mbox, unsigned chan, uint32_t data28)
-+{
-+ int rc;
-+
-+ if (mbox->magic != MBOX_MAGIC)
-+ rc = -EINVAL;
-+ else {
-+ /* wait for the mailbox FIFO to have some space in it */
-+ while (0 != (readl(mbox->status) & ARM_MS_FULL))
-+ cpu_relax();
-+
-+ writel(MBOX_MSG(chan, data28), mbox->write);
-+ rc = 0;
-+ }
-+ return rc;
-+}
-+
-+static int mbox_read(struct vc_mailbox *mbox, unsigned chan, uint32_t *data28)
-+{
-+ int rc;
-+
-+ if (mbox->magic != MBOX_MAGIC)
-+ rc = -EINVAL;
-+ else {
-+ down(&mbox->sema[chan]);
-+ *data28 = MBOX_DATA28(mbox->msg[chan]);
-+ mbox->msg[chan] = 0;
-+ rc = 0;
-+ }
-+ return rc;
-+}
-+
-+static irqreturn_t mbox_irq(int irq, void *dev_id)
-+{
-+ /* wait for the mailbox FIFO to have some data in it */
-+ struct vc_mailbox *mbox = (struct vc_mailbox *) dev_id;
-+ int status = readl(mbox->status);
-+ int ret = IRQ_NONE;
-+
-+ while (!(status & ARM_MS_EMPTY)) {
-+ uint32_t msg = readl(mbox->read);
-+ int chan = MBOX_CHAN(msg);
-+ if (chan < MBOX_CHAN_COUNT) {
-+ if (mbox->msg[chan]) {
-+ /* Overflow */
-+ printk(KERN_ERR DRIVER_NAME
-+ ": mbox chan %d overflow - drop %08x\n",
-+ chan, msg);
-+ } else {
-+ mbox->msg[chan] = (msg | 0xf);
-+ up(&mbox->sema[chan]);
-+ }
-+ } else {
-+ printk(KERN_ERR DRIVER_NAME
-+ ": invalid channel selector (msg %08x)\n", msg);
-+ }
-+ ret = IRQ_HANDLED;
-+ status = readl(mbox->status);
-+ }
-+ return ret;
-+}
-+
-+static struct irqaction mbox_irqaction = {
-+ .name = "ARM Mailbox IRQ",
-+ .flags = IRQF_DISABLED | IRQF_IRQPOLL,
-+ .handler = mbox_irq,
-+};
-+
-+/* ----------------------------------------------------------------------
-+ * Mailbox Methods
-+ * -------------------------------------------------------------------- */
-+
-+static struct device *mbox_dev; /* we assume there's only one! */
-+
-+static int dev_mbox_write(struct device *dev, unsigned chan, uint32_t data28)
-+{
-+ int rc;
-+
-+ struct vc_mailbox *mailbox = dev_get_drvdata(dev);
-+ device_lock(dev);
-+ rc = mbox_write(mailbox, chan, data28);
-+ device_unlock(dev);
-+
-+ return rc;
-+}
-+
-+static int dev_mbox_read(struct device *dev, unsigned chan, uint32_t *data28)
-+{
-+ int rc;
-+
-+ struct vc_mailbox *mailbox = dev_get_drvdata(dev);
-+ device_lock(dev);
-+ rc = mbox_read(mailbox, chan, data28);
-+ device_unlock(dev);
-+
-+ return rc;
-+}
-+
-+extern int bcm_mailbox_write(unsigned chan, uint32_t data28)
-+{
-+ if (mbox_dev)
-+ return dev_mbox_write(mbox_dev, chan, data28);
-+ else
-+ return -ENODEV;
-+}
-+EXPORT_SYMBOL_GPL(bcm_mailbox_write);
-+
-+extern int bcm_mailbox_read(unsigned chan, uint32_t *data28)
-+{
-+ if (mbox_dev)
-+ return dev_mbox_read(mbox_dev, chan, data28);
-+ else
-+ return -ENODEV;
-+}
-+EXPORT_SYMBOL_GPL(bcm_mailbox_read);
-+
-+static void dev_mbox_register(const char *dev_name, struct device *dev)
-+{
-+ mbox_dev = dev;
-+}
-+
-+static int mbox_copy_from_user(void *dst, const void *src, int size)
-+{
-+ if ( (uint32_t)src < TASK_SIZE)
-+ {
-+ return copy_from_user(dst, src, size);
-+ }
-+ else
-+ {
-+ memcpy( dst, src, size );
-+ return 0;
-+ }
-+}
-+
-+static int mbox_copy_to_user(void *dst, const void *src, int size)
-+{
-+ if ( (uint32_t)dst < TASK_SIZE)
-+ {
-+ return copy_to_user(dst, src, size);
-+ }
-+ else
-+ {
-+ memcpy( dst, src, size );
-+ return 0;
-+ }
-+}
-+
-+static DEFINE_MUTEX(mailbox_lock);
-+extern int bcm_mailbox_property(void *data, int size)
-+{
-+ uint32_t success;
-+ dma_addr_t mem_bus; /* the memory address accessed from videocore */
-+ void *mem_kern; /* the memory address accessed from driver */
-+ int s = 0;
-+
-+ mutex_lock(&mailbox_lock);
-+ /* allocate some memory for the messages communicating with GPU */
-+ mem_kern = dma_alloc_coherent(NULL, PAGE_ALIGN(size), &mem_bus, GFP_ATOMIC);
-+ if (mem_kern) {
-+ /* create the message */
-+ mbox_copy_from_user(mem_kern, data, size);
-+
-+ /* send the message */
-+ wmb();
-+ s = bcm_mailbox_write(MBOX_CHAN_PROPERTY, (uint32_t)mem_bus);
-+ if (s == 0) {
-+ s = bcm_mailbox_read(MBOX_CHAN_PROPERTY, &success);
-+ }
-+ if (s == 0) {
-+ /* copy the response */
-+ rmb();
-+ mbox_copy_to_user(data, mem_kern, size);
-+ }
-+ dma_free_coherent(NULL, PAGE_ALIGN(size), mem_kern, mem_bus);
-+ } else {
-+ s = -ENOMEM;
-+ }
-+ if (s != 0)
-+ printk(KERN_ERR DRIVER_NAME ": %s failed (%d)\n", __func__, s);
-+
-+ mutex_unlock(&mailbox_lock);
-+ return s;
-+}
-+EXPORT_SYMBOL_GPL(bcm_mailbox_property);
-+
-+/* ----------------------------------------------------------------------
-+ * Platform Device for Mailbox
-+ * -------------------------------------------------------------------- */
-+
-+/*
-+ * Is the device open right now? Used to prevent
-+ * concurent access into the same device
-+ */
-+static int Device_Open = 0;
-+
-+/*
-+ * This is called whenever a process attempts to open the device file
-+ */
-+static int device_open(struct inode *inode, struct file *file)
-+{
-+ /*
-+ * We don't want to talk to two processes at the same time
-+ */
-+ if (Device_Open)
-+ return -EBUSY;
-+
-+ Device_Open++;
-+ /*
-+ * Initialize the message
-+ */
-+ try_module_get(THIS_MODULE);
-+ return 0;
-+}
-+
-+static int device_release(struct inode *inode, struct file *file)
-+{
-+ /*
-+ * We're now ready for our next caller
-+ */
-+ Device_Open--;
-+
-+ module_put(THIS_MODULE);
-+ return 0;
-+}
-+
-+/*
-+ * This function is called whenever a process tries to do an ioctl on our
-+ * device file. We get two extra parameters (additional to the inode and file
-+ * structures, which all device functions get): the number of the ioctl called
-+ * and the parameter given to the ioctl function.
-+ *
-+ * If the ioctl is write or read/write (meaning output is returned to the
-+ * calling process), the ioctl call returns the output of this function.
-+ *
-+ */
-+static long device_ioctl(struct file *file, /* see include/linux/fs.h */
-+ unsigned int ioctl_num, /* number and param for ioctl */
-+ unsigned long ioctl_param)
-+{
-+ unsigned size;
-+ /*
-+ * Switch according to the ioctl called
-+ */
-+ switch (ioctl_num) {
-+ case IOCTL_MBOX_PROPERTY:
-+ /*
-+ * Receive a pointer to a message (in user space) and set that
-+ * to be the device's message. Get the parameter given to
-+ * ioctl by the process.
-+ */
-+ mbox_copy_from_user(&size, (void *)ioctl_param, sizeof size);
-+ return bcm_mailbox_property((void *)ioctl_param, size);
-+ break;
-+ default:
-+ printk(KERN_ERR DRIVER_NAME "unknown ioctl: %d\n", ioctl_num);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/* Module Declarations */
-+
-+/*
-+ * This structure will hold the functions to be called
-+ * when a process does something to the device we
-+ * created. Since a pointer to this structure is kept in
-+ * the devices table, it can't be local to
-+ * init_module. NULL is for unimplemented functios.
-+ */
-+struct file_operations fops = {
-+ .unlocked_ioctl = device_ioctl,
-+ .open = device_open,
-+ .release = device_release, /* a.k.a. close */
-+};
-+
-+static int bcm_vcio_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+ struct vc_mailbox *mailbox;
-+
-+ mailbox = kzalloc(sizeof(*mailbox), GFP_KERNEL);
-+ if (NULL == mailbox) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to allocate "
-+ "mailbox memory\n");
-+ ret = -ENOMEM;
-+ } else {
-+ struct resource *res;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (res == NULL) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to obtain memory "
-+ "resource\n");
-+ ret = -ENODEV;
-+ kfree(mailbox);
-+ } else {
-+ /* should be based on the registers from res really */
-+ mbox_init(mailbox, &pdev->dev, ARM_0_MAIL0_RD);
-+
-+ platform_set_drvdata(pdev, mailbox);
-+ dev_mbox_register(DRIVER_NAME, &pdev->dev);
-+
-+ mbox_irqaction.dev_id = mailbox;
-+ setup_irq(IRQ_ARM_MAILBOX, &mbox_irqaction);
-+ printk(KERN_INFO DRIVER_NAME ": mailbox at %p\n",
-+ __io_address(ARM_0_MAIL0_RD));
-+ }
-+ }
-+
-+ if (ret == 0) {
-+ /*
-+ * Register the character device
-+ */
-+ ret = register_chrdev(MAJOR_NUM, DEVICE_FILE_NAME, &fops);
-+
-+ /*
-+ * Negative values signify an error
-+ */
-+ if (ret < 0) {
-+ printk(KERN_ERR DRIVER_NAME
-+ "Failed registering the character device %d\n", ret);
-+ return ret;
-+ }
-+ }
-+ return ret;
-+}
-+
-+static int bcm_vcio_remove(struct platform_device *pdev)
-+{
-+ struct vc_mailbox *mailbox = platform_get_drvdata(pdev);
-+
-+ platform_set_drvdata(pdev, NULL);
-+ kfree(mailbox);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm_mbox_driver = {
-+ .probe = bcm_vcio_probe,
-+ .remove = bcm_vcio_remove,
-+
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init bcm_mbox_init(void)
-+{
-+ int ret;
-+
-+ printk(KERN_INFO "mailbox: Broadcom VideoCore Mailbox driver\n");
-+
-+ ret = platform_driver_register(&bcm_mbox_driver);
-+ if (ret != 0) {
-+ printk(KERN_ERR DRIVER_NAME ": failed to register "
-+ "on platform\n");
-+ }
-+
-+ return ret;
-+}
-+
-+static void __exit bcm_mbox_exit(void)
-+{
-+ platform_driver_unregister(&bcm_mbox_driver);
-+}
-+
-+arch_initcall(bcm_mbox_init); /* Initialize early */
-+module_exit(bcm_mbox_exit);
-+
-+MODULE_AUTHOR("Gray Girling");
-+MODULE_DESCRIPTION("ARM I/O to VideoCore processor");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:bcm-mbox");
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/vc_mem.c linux-3.11.10/arch/arm/mach-bcm2708/vc_mem.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/vc_mem.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/vc_mem.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,462 @@
-+/*****************************************************************************
-+* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/cdev.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/proc_fs.h>
-+#include <asm/uaccess.h>
-+#include <linux/dma-mapping.h>
-+
-+#ifdef CONFIG_ARCH_KONA
-+#include <chal/chal_ipc.h>
-+#elif CONFIG_ARCH_BCM2708
-+#else
-+#include <csp/chal_ipc.h>
-+#endif
-+
-+#include "mach/vc_mem.h"
-+#include <mach/vcio.h>
-+
-+#define DRIVER_NAME "vc-mem"
-+
-+// Uncomment to enable debug logging
-+// #define ENABLE_DBG
-+
-+#if defined(ENABLE_DBG)
-+#define LOG_DBG( fmt, ... ) printk( KERN_INFO fmt "\n", ##__VA_ARGS__ )
-+#else
-+#define LOG_DBG( fmt, ... )
-+#endif
-+#define LOG_ERR( fmt, ... ) printk( KERN_ERR fmt "\n", ##__VA_ARGS__ )
-+
-+// Device (/dev) related variables
-+static dev_t vc_mem_devnum = 0;
-+static struct class *vc_mem_class = NULL;
-+static struct cdev vc_mem_cdev;
-+static int vc_mem_inited = 0;
-+
-+// Proc entry
-+static struct proc_dir_entry *vc_mem_proc_entry;
-+
-+/*
-+ * Videocore memory addresses and size
-+ *
-+ * Drivers that wish to know the videocore memory addresses and sizes should
-+ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
-+ * headers. This allows the other drivers to not be tied down to a a certain
-+ * address/size at compile time.
-+ *
-+ * In the future, the goal is to have the videocore memory virtual address and
-+ * size be calculated at boot time rather than at compile time. The decision of
-+ * where the videocore memory resides and its size would be in the hands of the
-+ * bootloader (and/or kernel). When that happens, the values of these variables
-+ * would be calculated and assigned in the init function.
-+ */
-+// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
-+unsigned long mm_vc_mem_phys_addr = 0x00000000;
-+unsigned int mm_vc_mem_size = 0;
-+unsigned int mm_vc_mem_base = 0;
-+
-+EXPORT_SYMBOL(mm_vc_mem_phys_addr);
-+EXPORT_SYMBOL(mm_vc_mem_size);
-+EXPORT_SYMBOL(mm_vc_mem_base);
-+
-+static uint phys_addr = 0;
-+static uint mem_size = 0;
-+static uint mem_base = 0;
-+
-+
-+/****************************************************************************
-+*
-+* vc_mem_open
-+*
-+***************************************************************************/
-+
-+static int
-+vc_mem_open(struct inode *inode, struct file *file)
-+{
-+ (void) inode;
-+ (void) file;
-+
-+ LOG_DBG("%s: called file = 0x%p", __func__, file);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_release
-+*
-+***************************************************************************/
-+
-+static int
-+vc_mem_release(struct inode *inode, struct file *file)
-+{
-+ (void) inode;
-+ (void) file;
-+
-+ LOG_DBG("%s: called file = 0x%p", __func__, file);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_get_size
-+*
-+***************************************************************************/
-+
-+static void
-+vc_mem_get_size(void)
-+{
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_get_base
-+*
-+***************************************************************************/
-+
-+static void
-+vc_mem_get_base(void)
-+{
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_get_current_size
-+*
-+***************************************************************************/
-+
-+int
-+vc_mem_get_current_size(void)
-+{
-+ return mm_vc_mem_size;
-+}
-+
-+EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
-+
-+/****************************************************************************
-+*
-+* vc_mem_ioctl
-+*
-+***************************************************************************/
-+
-+static long
-+vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int rc = 0;
-+
-+ (void) cmd;
-+ (void) arg;
-+
-+ LOG_DBG("%s: called file = 0x%p", __func__, file);
-+
-+ switch (cmd) {
-+ case VC_MEM_IOC_MEM_PHYS_ADDR:
-+ {
-+ LOG_DBG("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p",
-+ __func__, (void *) mm_vc_mem_phys_addr);
-+
-+ if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
-+ sizeof (mm_vc_mem_phys_addr)) != 0) {
-+ rc = -EFAULT;
-+ }
-+ break;
-+ }
-+ case VC_MEM_IOC_MEM_SIZE:
-+ {
-+ // Get the videocore memory size first
-+ vc_mem_get_size();
-+
-+ LOG_DBG("%s: VC_MEM_IOC_MEM_SIZE=%u", __func__,
-+ mm_vc_mem_size);
-+
-+ if (copy_to_user((void *) arg, &mm_vc_mem_size,
-+ sizeof (mm_vc_mem_size)) != 0) {
-+ rc = -EFAULT;
-+ }
-+ break;
-+ }
-+ case VC_MEM_IOC_MEM_BASE:
-+ {
-+ // Get the videocore memory base
-+ vc_mem_get_base();
-+
-+ LOG_DBG("%s: VC_MEM_IOC_MEM_BASE=%u", __func__,
-+ mm_vc_mem_base);
-+
-+ if (copy_to_user((void *) arg, &mm_vc_mem_base,
-+ sizeof (mm_vc_mem_base)) != 0) {
-+ rc = -EFAULT;
-+ }
-+ break;
-+ }
-+ case VC_MEM_IOC_MEM_LOAD:
-+ {
-+ // Get the videocore memory base
-+ vc_mem_get_base();
-+
-+ LOG_DBG("%s: VC_MEM_IOC_MEM_LOAD=%u", __func__,
-+ mm_vc_mem_base);
-+
-+ if (copy_to_user((void *) arg, &mm_vc_mem_base,
-+ sizeof (mm_vc_mem_base)) != 0) {
-+ rc = -EFAULT;
-+ }
-+ break;
-+ }
-+ default:
-+ {
-+ return -ENOTTY;
-+ }
-+ }
-+ LOG_DBG("%s: file = 0x%p returning %d", __func__, file, rc);
-+
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_mmap
-+*
-+***************************************************************************/
-+
-+static int
-+vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
-+{
-+ int rc = 0;
-+ unsigned long length = vma->vm_end - vma->vm_start;
-+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-+
-+ LOG_DBG("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx",
-+ __func__, (long) vma->vm_start, (long) vma->vm_end,
-+ (long) vma->vm_pgoff);
-+
-+ if (offset + length > mm_vc_mem_size) {
-+ LOG_ERR("%s: length %ld is too big", __func__, length);
-+ return -EINVAL;
-+ }
-+ // Do not cache the memory map
-+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-+
-+ rc = remap_pfn_range(vma, vma->vm_start,
-+ (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
-+ vma->vm_pgoff, length, vma->vm_page_prot);
-+ if (rc != 0) {
-+ LOG_ERR("%s: remap_pfn_range failed (rc=%d)", __func__, rc);
-+ }
-+
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* File Operations for the driver.
-+*
-+***************************************************************************/
-+
-+static const struct file_operations vc_mem_fops = {
-+ .owner = THIS_MODULE,
-+ .open = vc_mem_open,
-+ .release = vc_mem_release,
-+ .unlocked_ioctl = vc_mem_ioctl,
-+ .mmap = vc_mem_mmap,
-+};
-+
-+/****************************************************************************
-+*
-+* vc_mem_proc_read
-+*
-+***************************************************************************/
-+
-+static int
-+vc_mem_proc_read(char *buf, char **start, off_t offset, int count, int *eof,
-+ void *data)
-+{
-+ char *p = buf;
-+
-+ (void) start;
-+ (void) count;
-+ (void) data;
-+
-+ if (offset > 0) {
-+ *eof = 1;
-+ return 0;
-+ }
-+ // Get the videocore memory size first
-+ vc_mem_get_size();
-+
-+ p += sprintf(p, "Videocore memory:\n");
-+ if (mm_vc_mem_phys_addr != 0)
-+ p += sprintf(p, " Physical address: 0x%p\n",
-+ (void *) mm_vc_mem_phys_addr);
-+ else
-+ p += sprintf(p, " Physical address: 0x00000000\n");
-+ p += sprintf(p, " Length (bytes): %u\n", mm_vc_mem_size);
-+
-+ *eof = 1;
-+ return p - buf;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_proc_write
-+*
-+***************************************************************************/
-+
-+static int
-+vc_mem_proc_write(struct file *file, const char __user * buffer,
-+ unsigned long count, void *data)
-+{
-+ int rc = -EFAULT;
-+ char input_str[10];
-+
-+ memset(input_str, 0, sizeof (input_str));
-+
-+ if (count > sizeof (input_str)) {
-+ LOG_ERR("%s: input string length too long", __func__);
-+ goto out;
-+ }
-+
-+ if (copy_from_user(input_str, buffer, count - 1)) {
-+ LOG_ERR("%s: failed to get input string", __func__);
-+ goto out;
-+ }
-+
-+ if (strncmp(input_str, "connect", strlen("connect")) == 0) {
-+ // Get the videocore memory size from the videocore
-+ vc_mem_get_size();
-+ }
-+
-+ out:
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_init
-+*
-+***************************************************************************/
-+
-+static int __init
-+vc_mem_init(void)
-+{
-+ int rc = -EFAULT;
-+ struct device *dev;
-+
-+ LOG_DBG("%s: called", __func__);
-+
-+ mm_vc_mem_phys_addr = phys_addr;
-+ mm_vc_mem_size = mem_size;
-+ mm_vc_mem_base = mem_base;
-+
-+ vc_mem_get_size();
-+
-+ printk("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
-+ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
-+
-+ if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
-+ LOG_ERR("%s: alloc_chrdev_region failed (rc=%d)", __func__, rc);
-+ goto out_err;
-+ }
-+
-+ cdev_init(&vc_mem_cdev, &vc_mem_fops);
-+ if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
-+ LOG_ERR("%s: cdev_add failed (rc=%d)", __func__, rc);
-+ goto out_unregister;
-+ }
-+
-+ vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
-+ if (IS_ERR(vc_mem_class)) {
-+ rc = PTR_ERR(vc_mem_class);
-+ LOG_ERR("%s: class_create failed (rc=%d)", __func__, rc);
-+ goto out_cdev_del;
-+ }
-+
-+ dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
-+ DRIVER_NAME);
-+ if (IS_ERR(dev)) {
-+ rc = PTR_ERR(dev);
-+ LOG_ERR("%s: device_create failed (rc=%d)", __func__, rc);
-+ goto out_class_destroy;
-+ }
-+
-+#if 0
-+ vc_mem_proc_entry = create_proc_entry(DRIVER_NAME, 0444, NULL);
-+ if (vc_mem_proc_entry == NULL) {
-+ rc = -EFAULT;
-+ LOG_ERR("%s: create_proc_entry failed", __func__);
-+ goto out_device_destroy;
-+ }
-+ vc_mem_proc_entry->read_proc = vc_mem_proc_read;
-+ vc_mem_proc_entry->write_proc = vc_mem_proc_write;
-+#endif
-+
-+ vc_mem_inited = 1;
-+ return 0;
-+
-+ out_device_destroy:
-+ device_destroy(vc_mem_class, vc_mem_devnum);
-+
-+ out_class_destroy:
-+ class_destroy(vc_mem_class);
-+ vc_mem_class = NULL;
-+
-+ out_cdev_del:
-+ cdev_del(&vc_mem_cdev);
-+
-+ out_unregister:
-+ unregister_chrdev_region(vc_mem_devnum, 1);
-+
-+ out_err:
-+ return -1;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_mem_exit
-+*
-+***************************************************************************/
-+
-+static void __exit
-+vc_mem_exit(void)
-+{
-+ LOG_DBG("%s: called", __func__);
-+
-+ if (vc_mem_inited) {
-+#if 0
-+ remove_proc_entry(vc_mem_proc_entry->name, NULL);
-+#endif
-+ device_destroy(vc_mem_class, vc_mem_devnum);
-+ class_destroy(vc_mem_class);
-+ cdev_del(&vc_mem_cdev);
-+ unregister_chrdev_region(vc_mem_devnum, 1);
-+ }
-+}
-+
-+module_init(vc_mem_init);
-+module_exit(vc_mem_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Broadcom Corporation");
-+
-+module_param(phys_addr, uint, 0644);
-+module_param(mem_size, uint, 0644);
-+module_param(mem_base, uint, 0644);
-+
-diff -Nur linux-3.11.10.orig/arch/arm/mach-bcm2708/vc_support.c linux-3.11.10/arch/arm/mach-bcm2708/vc_support.c
---- linux-3.11.10.orig/arch/arm/mach-bcm2708/vc_support.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/arch/arm/mach-bcm2708/vc_support.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,318 @@
-+/*
-+ * vc_support.c
-+ *
-+ * Created on: 25 Nov 2012
-+ * Author: Simon
-+ */
-+
-+#include <linux/module.h>
-+#include <mach/vcio.h>
-+
-+#ifdef ECLIPSE_IGNORE
-+
-+#define __user
-+#define __init
-+#define __exit
-+#define __iomem
-+#define KERN_DEBUG
-+#define KERN_ERR
-+#define KERN_WARNING
-+#define KERN_INFO
-+#define _IOWR(a, b, c) b
-+#define _IOW(a, b, c) b
-+#define _IO(a, b) b
-+
-+#endif
-+
-+/****** VC MAILBOX FUNCTIONALITY ******/
-+unsigned int AllocateVcMemory(unsigned int *pHandle, unsigned int size, unsigned int alignment, unsigned int flags)
-+{
-+ struct vc_msg
-+ {
-+ unsigned int m_msgSize;
-+ unsigned int m_response;
-+
-+ struct vc_tag
-+ {
-+ unsigned int m_tagId;
-+ unsigned int m_sendBufferSize;
-+ union {
-+ unsigned int m_sendDataSize;
-+ unsigned int m_recvDataSize;
-+ };
-+
-+ struct args
-+ {
-+ union {
-+ unsigned int m_size;
-+ unsigned int m_handle;
-+ };
-+ unsigned int m_alignment;
-+ unsigned int m_flags;
-+ } m_args;
-+ } m_tag;
-+
-+ unsigned int m_endTag;
-+ } msg;
-+ int s;
-+
-+ msg.m_msgSize = sizeof(msg);
-+ msg.m_response = 0;
-+ msg.m_endTag = 0;
-+
-+ //fill in the tag for the allocation command
-+ msg.m_tag.m_tagId = 0x3000c;
-+ msg.m_tag.m_sendBufferSize = 12;
-+ msg.m_tag.m_sendDataSize = 12;
-+
-+ //fill in our args
-+ msg.m_tag.m_args.m_size = size;
-+ msg.m_tag.m_args.m_alignment = alignment;
-+ msg.m_tag.m_args.m_flags = flags;
-+
-+ //run the command
-+ s = bcm_mailbox_property(&msg, sizeof(msg));
-+
-+ if (s == 0 && msg.m_response == 0x80000000 && msg.m_tag.m_recvDataSize == 0x80000004)
-+ {
-+ *pHandle = msg.m_tag.m_args.m_handle;
-+ return 0;
-+ }
-+ else
-+ {
-+ printk(KERN_ERR "failed to allocate vc memory: s=%d response=%08x recv data size=%08x\n",
-+ s, msg.m_response, msg.m_tag.m_recvDataSize);
-+ return 1;
-+ }
-+}
-+
-+unsigned int ReleaseVcMemory(unsigned int handle)
-+{
-+ struct vc_msg
-+ {
-+ unsigned int m_msgSize;
-+ unsigned int m_response;
-+
-+ struct vc_tag
-+ {
-+ unsigned int m_tagId;
-+ unsigned int m_sendBufferSize;
-+ union {
-+ unsigned int m_sendDataSize;
-+ unsigned int m_recvDataSize;
-+ };
-+
-+ struct args
-+ {
-+ union {
-+ unsigned int m_handle;
-+ unsigned int m_error;
-+ };
-+ } m_args;
-+ } m_tag;
-+
-+ unsigned int m_endTag;
-+ } msg;
-+ int s;
-+
-+ msg.m_msgSize = sizeof(msg);
-+ msg.m_response = 0;
-+ msg.m_endTag = 0;
-+
-+ //fill in the tag for the release command
-+ msg.m_tag.m_tagId = 0x3000f;
-+ msg.m_tag.m_sendBufferSize = 4;
-+ msg.m_tag.m_sendDataSize = 4;
-+
-+ //pass across the handle
-+ msg.m_tag.m_args.m_handle = handle;
-+
-+ s = bcm_mailbox_property(&msg, sizeof(msg));
-+
-+ if (s == 0 && msg.m_response == 0x80000000 && msg.m_tag.m_recvDataSize == 0x80000004 && msg.m_tag.m_args.m_error == 0)
-+ return 0;
-+ else
-+ {
-+ printk(KERN_ERR "failed to release vc memory: s=%d response=%08x recv data size=%08x error=%08x\n",
-+ s, msg.m_response, msg.m_tag.m_recvDataSize, msg.m_tag.m_args.m_error);
-+ return 1;
-+ }
-+}
-+
-+unsigned int LockVcMemory(unsigned int *pBusAddress, unsigned int handle)
-+{
-+ struct vc_msg
-+ {
-+ unsigned int m_msgSize;
-+ unsigned int m_response;
-+
-+ struct vc_tag
-+ {
-+ unsigned int m_tagId;
-+ unsigned int m_sendBufferSize;
-+ union {
-+ unsigned int m_sendDataSize;
-+ unsigned int m_recvDataSize;
-+ };
-+
-+ struct args
-+ {
-+ union {
-+ unsigned int m_handle;
-+ unsigned int m_busAddress;
-+ };
-+ } m_args;
-+ } m_tag;
-+
-+ unsigned int m_endTag;
-+ } msg;
-+ int s;
-+
-+ msg.m_msgSize = sizeof(msg);
-+ msg.m_response = 0;
-+ msg.m_endTag = 0;
-+
-+ //fill in the tag for the lock command
-+ msg.m_tag.m_tagId = 0x3000d;
-+ msg.m_tag.m_sendBufferSize = 4;
-+ msg.m_tag.m_sendDataSize = 4;
-+
-+ //pass across the handle
-+ msg.m_tag.m_args.m_handle = handle;
-+
-+ s = bcm_mailbox_property(&msg, sizeof(msg));
-+
-+ if (s == 0 && msg.m_response == 0x80000000 && msg.m_tag.m_recvDataSize == 0x80000004)
-+ {
-+ //pick out the bus address
-+ *pBusAddress = msg.m_tag.m_args.m_busAddress;
-+ return 0;
-+ }
-+ else
-+ {
-+ printk(KERN_ERR "failed to lock vc memory: s=%d response=%08x recv data size=%08x\n",
-+ s, msg.m_response, msg.m_tag.m_recvDataSize);
-+ return 1;
-+ }
-+}
-+
-+unsigned int UnlockVcMemory(unsigned int handle)
-+{
-+ struct vc_msg
-+ {
-+ unsigned int m_msgSize;
-+ unsigned int m_response;
-+
-+ struct vc_tag
-+ {
-+ unsigned int m_tagId;
-+ unsigned int m_sendBufferSize;
-+ union {
-+ unsigned int m_sendDataSize;
-+ unsigned int m_recvDataSize;
-+ };
-+
-+ struct args
-+ {
-+ union {
-+ unsigned int m_handle;
-+ unsigned int m_error;
-+ };
-+ } m_args;
-+ } m_tag;
-+
-+ unsigned int m_endTag;
-+ } msg;
-+ int s;
-+
-+ msg.m_msgSize = sizeof(msg);
-+ msg.m_response = 0;
-+ msg.m_endTag = 0;
-+
-+ //fill in the tag for the unlock command
-+ msg.m_tag.m_tagId = 0x3000e;
-+ msg.m_tag.m_sendBufferSize = 4;
-+ msg.m_tag.m_sendDataSize = 4;
-+
-+ //pass across the handle
-+ msg.m_tag.m_args.m_handle = handle;
-+
-+ s = bcm_mailbox_property(&msg, sizeof(msg));
-+
-+ //check the error code too
-+ if (s == 0 && msg.m_response == 0x80000000 && msg.m_tag.m_recvDataSize == 0x80000004 && msg.m_tag.m_args.m_error == 0)
-+ return 0;
-+ else
-+ {
-+ printk(KERN_ERR "failed to unlock vc memory: s=%d response=%08x recv data size=%08x error%08x\n",
-+ s, msg.m_response, msg.m_tag.m_recvDataSize, msg.m_tag.m_args.m_error);
-+ return 1;
-+ }
-+}
-+
-+unsigned int ExecuteVcCode(unsigned int code,
-+ unsigned int r0, unsigned int r1, unsigned int r2, unsigned int r3, unsigned int r4, unsigned int r5)
-+{
-+ struct vc_msg
-+ {
-+ unsigned int m_msgSize;
-+ unsigned int m_response;
-+
-+ struct vc_tag
-+ {
-+ unsigned int m_tagId;
-+ unsigned int m_sendBufferSize;
-+ union {
-+ unsigned int m_sendDataSize;
-+ unsigned int m_recvDataSize;
-+ };
-+
-+ struct args
-+ {
-+ union {
-+ unsigned int m_pCode;
-+ unsigned int m_return;
-+ };
-+ unsigned int m_r0;
-+ unsigned int m_r1;
-+ unsigned int m_r2;
-+ unsigned int m_r3;
-+ unsigned int m_r4;
-+ unsigned int m_r5;
-+ } m_args;
-+ } m_tag;
-+
-+ unsigned int m_endTag;
-+ } msg;
-+ int s;
-+
-+ msg.m_msgSize = sizeof(msg);
-+ msg.m_response = 0;
-+ msg.m_endTag = 0;
-+
-+ //fill in the tag for the unlock command
-+ msg.m_tag.m_tagId = 0x30010;
-+ msg.m_tag.m_sendBufferSize = 28;
-+ msg.m_tag.m_sendDataSize = 28;
-+
-+ //pass across the handle
-+ msg.m_tag.m_args.m_pCode = code;
-+ msg.m_tag.m_args.m_r0 = r0;
-+ msg.m_tag.m_args.m_r1 = r1;
-+ msg.m_tag.m_args.m_r2 = r2;
-+ msg.m_tag.m_args.m_r3 = r3;
-+ msg.m_tag.m_args.m_r4 = r4;
-+ msg.m_tag.m_args.m_r5 = r5;
-+
-+ s = bcm_mailbox_property(&msg, sizeof(msg));
-+
-+ //check the error code too
-+ if (s == 0 && msg.m_response == 0x80000000 && msg.m_tag.m_recvDataSize == 0x80000004)
-+ return msg.m_tag.m_args.m_return;
-+ else
-+ {
-+ printk(KERN_ERR "failed to execute: s=%d response=%08x recv data size=%08x\n",
-+ s, msg.m_response, msg.m_tag.m_recvDataSize);
-+ return 1;
-+ }
-+}
-diff -Nur linux-3.11.10.orig/arch/arm/Makefile linux-3.11.10/arch/arm/Makefile
---- linux-3.11.10.orig/arch/arm/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -146,6 +146,7 @@
- # by CONFIG_* macro name.
- machine-$(CONFIG_ARCH_AT91) += at91
- machine-$(CONFIG_ARCH_BCM) += bcm
-+machine-$(CONFIG_ARCH_BCM2708) += bcm2708
- machine-$(CONFIG_ARCH_BCM2835) += bcm2835
- machine-$(CONFIG_ARCH_CLPS711X) += clps711x
- machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx
-diff -Nur linux-3.11.10.orig/arch/arm/mm/Kconfig linux-3.11.10/arch/arm/mm/Kconfig
---- linux-3.11.10.orig/arch/arm/mm/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/mm/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -358,7 +358,7 @@
-
- # ARMv6
- config CPU_V6
-- bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
-+ bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX || MACH_BCM2708
- select CPU_32v6
- select CPU_ABRT_EV6
- select CPU_CACHE_V6
-diff -Nur linux-3.11.10.orig/arch/arm/mm/proc-v6.S linux-3.11.10/arch/arm/mm/proc-v6.S
---- linux-3.11.10.orig/arch/arm/mm/proc-v6.S 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/mm/proc-v6.S 2014-02-07 19:57:28.000000000 +0100
-@@ -73,10 +73,19 @@
- *
- * IRQs are already disabled.
- */
-+
-+/* See jira SW-5991 for details of this workaround */
- ENTRY(cpu_v6_do_idle)
-- mov r1, #0
-- mcr p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
-- mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt
-+ .align 5
-+ mov r1, #2
-+1: subs r1, #1
-+ nop
-+ mcreq p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
-+ mcreq p15, 0, r1, c7, c0, 4 @ wait for interrupt
-+ nop
-+ nop
-+ nop
-+ bne 1b
- mov pc, lr
-
- ENTRY(cpu_v6_dcache_clean_area)
-diff -Nur linux-3.11.10.orig/arch/arm/tools/mach-types linux-3.11.10/arch/arm/tools/mach-types
---- linux-3.11.10.orig/arch/arm/tools/mach-types 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/arm/tools/mach-types 2014-02-07 19:57:28.000000000 +0100
-@@ -522,6 +522,7 @@
- prima2_evb MACH_PRIMA2_EVB PRIMA2_EVB 3103
- paz00 MACH_PAZ00 PAZ00 3128
- acmenetusfoxg20 MACH_ACMENETUSFOXG20 ACMENETUSFOXG20 3129
-+bcm2708 MACH_BCM2708 BCM2708 3138
- ag5evm MACH_AG5EVM AG5EVM 3189
- ics_if_voip MACH_ICS_IF_VOIP ICS_IF_VOIP 3206
- wlf_cragg_6410 MACH_WLF_CRAGG_6410 WLF_CRAGG_6410 3207
-diff -Nur linux-3.11.10.orig/drivers/char/broadcom/Kconfig linux-3.11.10/drivers/char/broadcom/Kconfig
---- linux-3.11.10.orig/drivers/char/broadcom/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/char/broadcom/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,16 @@
-+#
-+# Broadcom char driver config
-+#
-+
-+menuconfig BRCM_CHAR_DRIVERS
-+ bool "Broadcom Char Drivers"
-+ help
-+ Broadcom's char drivers
-+
-+config BCM_VC_CMA
-+ bool "Videocore CMA"
-+ depends on CMA && BRCM_CHAR_DRIVERS
-+ default n
-+ help
-+ Helper for videocore CMA access.
-+
-diff -Nur linux-3.11.10.orig/drivers/char/broadcom/Makefile linux-3.11.10/drivers/char/broadcom/Makefile
---- linux-3.11.10.orig/drivers/char/broadcom/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/char/broadcom/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1 @@
-+obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
-diff -Nur linux-3.11.10.orig/drivers/char/broadcom/vc_cma/Makefile linux-3.11.10/drivers/char/broadcom/vc_cma/Makefile
---- linux-3.11.10.orig/drivers/char/broadcom/vc_cma/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/char/broadcom/vc_cma/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,14 @@
-+EXTRA_CFLAGS += -Wall -Wstrict-prototypes -Wno-trigraphs
-+EXTRA_CFLAGS += -Werror
-+EXTRA_CFLAGS += -I"include/linux/broadcom"
-+EXTRA_CFLAGS += -I"drivers/misc/vc04_services"
-+EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchi"
-+EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchiq_arm"
-+
-+EXTRA_CFLAGS += -D__KERNEL__
-+EXTRA_CFLAGS += -D__linux__
-+EXTRA_CFLAGS += -Werror
-+
-+obj-$(CONFIG_BCM_VC_CMA) += vc-cma.o
-+
-+vc-cma-objs := vc_cma.o
-diff -Nur linux-3.11.10.orig/drivers/char/broadcom/vc_cma/vc_cma.c linux-3.11.10/drivers/char/broadcom/vc_cma/vc_cma.c
---- linux-3.11.10.orig/drivers/char/broadcom/vc_cma/vc_cma.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/char/broadcom/vc_cma/vc_cma.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,1143 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/kthread.h>
-+#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/cdev.h>
-+#include <linux/mm.h>
-+#include <linux/proc_fs.h>
-+#include <linux/seq_file.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-contiguous.h>
-+#include <linux/platform_device.h>
-+#include <linux/uaccess.h>
-+#include <asm/cacheflush.h>
-+
-+#include "vc_cma.h"
-+
-+#include "vchiq_util.h"
-+#include "vchiq_connected.h"
-+//#include "debug_sym.h"
-+//#include "vc_mem.h"
-+
-+#define DRIVER_NAME "vc-cma"
-+
-+#define LOG_DBG(fmt, ...) \
-+ if (vc_cma_debug) \
-+ printk(KERN_INFO fmt "\n", ##__VA_ARGS__)
-+#define LOG_ERR(fmt, ...) \
-+ printk(KERN_ERR fmt "\n", ##__VA_ARGS__)
-+
-+#define VC_CMA_FOURCC VCHIQ_MAKE_FOURCC('C', 'M', 'A', ' ')
-+#define VC_CMA_VERSION 2
-+
-+#define VC_CMA_CHUNK_ORDER 6 /* 256K */
-+#define VC_CMA_CHUNK_SIZE (4096 << VC_CMA_CHUNK_ORDER)
-+#define VC_CMA_MAX_PARAMS_PER_MSG \
-+ ((VCHIQ_MAX_MSG_SIZE - sizeof(unsigned short))/sizeof(unsigned short))
-+#define VC_CMA_RESERVE_COUNT_MAX 16
-+
-+#define PAGES_PER_CHUNK (VC_CMA_CHUNK_SIZE / PAGE_SIZE)
-+
-+#define VCADDR_TO_PHYSADDR(vcaddr) (mm_vc_mem_phys_addr + vcaddr)
-+
-+#define loud_error(...) \
-+ LOG_ERR("===== " __VA_ARGS__)
-+
-+enum {
-+ VC_CMA_MSG_QUIT,
-+ VC_CMA_MSG_OPEN,
-+ VC_CMA_MSG_TICK,
-+ VC_CMA_MSG_ALLOC, /* chunk count */
-+ VC_CMA_MSG_FREE, /* chunk, chunk, ... */
-+ VC_CMA_MSG_ALLOCATED, /* chunk, chunk, ... */
-+ VC_CMA_MSG_REQUEST_ALLOC, /* chunk count */
-+ VC_CMA_MSG_REQUEST_FREE, /* chunk count */
-+ VC_CMA_MSG_RESERVE, /* bytes lo, bytes hi */
-+ VC_CMA_MSG_UPDATE_RESERVE,
-+ VC_CMA_MSG_MAX
-+};
-+
-+struct cma_msg {
-+ unsigned short type;
-+ unsigned short params[VC_CMA_MAX_PARAMS_PER_MSG];
-+};
-+
-+struct vc_cma_reserve_user {
-+ unsigned int pid;
-+ unsigned int reserve;
-+};
-+
-+/* Device (/dev) related variables */
-+static dev_t vc_cma_devnum;
-+static struct class *vc_cma_class;
-+static struct cdev vc_cma_cdev;
-+static int vc_cma_inited;
-+static int vc_cma_debug;
-+
-+/* Proc entry */
-+static struct proc_dir_entry *vc_cma_proc_entry;
-+
-+phys_addr_t vc_cma_base;
-+struct page *vc_cma_base_page;
-+unsigned int vc_cma_size;
-+EXPORT_SYMBOL(vc_cma_size);
-+unsigned int vc_cma_initial;
-+unsigned int vc_cma_chunks;
-+unsigned int vc_cma_chunks_used;
-+unsigned int vc_cma_chunks_reserved;
-+
-+static int in_loud_error;
-+
-+unsigned int vc_cma_reserve_total;
-+unsigned int vc_cma_reserve_count;
-+struct vc_cma_reserve_user vc_cma_reserve_users[VC_CMA_RESERVE_COUNT_MAX];
-+static DEFINE_SEMAPHORE(vc_cma_reserve_mutex);
-+static DEFINE_SEMAPHORE(vc_cma_worker_queue_push_mutex);
-+
-+static u64 vc_cma_dma_mask = DMA_BIT_MASK(32);
-+static struct platform_device vc_cma_device = {
-+ .name = "vc-cma",
-+ .id = 0,
-+ .dev = {
-+ .dma_mask = &vc_cma_dma_mask,
-+ .coherent_dma_mask = DMA_BIT_MASK(32),
-+ },
-+};
-+
-+static VCHIQ_INSTANCE_T cma_instance;
-+static VCHIQ_SERVICE_HANDLE_T cma_service;
-+static VCHIU_QUEUE_T cma_msg_queue;
-+static struct task_struct *cma_worker;
-+
-+static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid);
-+static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply);
-+static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T * header,
-+ VCHIQ_SERVICE_HANDLE_T service,
-+ void *bulk_userdata);
-+static void send_vc_msg(unsigned short type,
-+ unsigned short param1, unsigned short param2);
-+static bool send_worker_msg(VCHIQ_HEADER_T * msg);
-+
-+static int early_vc_cma_mem(char *p)
-+{
-+ unsigned int new_size;
-+ printk(KERN_NOTICE "early_vc_cma_mem(%s)", p);
-+ vc_cma_size = memparse(p, &p);
-+ vc_cma_initial = vc_cma_size;
-+ if (*p == '/')
-+ vc_cma_size = memparse(p + 1, &p);
-+ if (*p == '@')
-+ vc_cma_base = memparse(p + 1, &p);
-+
-+ new_size = (vc_cma_size - ((-vc_cma_base) & (VC_CMA_CHUNK_SIZE - 1)))
-+ & ~(VC_CMA_CHUNK_SIZE - 1);
-+ if (new_size > vc_cma_size)
-+ vc_cma_size = 0;
-+ vc_cma_initial = (vc_cma_initial + VC_CMA_CHUNK_SIZE - 1)
-+ & ~(VC_CMA_CHUNK_SIZE - 1);
-+ if (vc_cma_initial > vc_cma_size)
-+ vc_cma_initial = vc_cma_size;
-+ vc_cma_base = (vc_cma_base + VC_CMA_CHUNK_SIZE - 1)
-+ & ~(VC_CMA_CHUNK_SIZE - 1);
-+
-+ printk(KERN_NOTICE " -> initial %x, size %x, base %x", vc_cma_initial,
-+ vc_cma_size, (unsigned int)vc_cma_base);
-+
-+ return 0;
-+}
-+
-+early_param("vc-cma-mem", early_vc_cma_mem);
-+
-+void vc_cma_early_init(void)
-+{
-+ LOG_DBG("vc_cma_early_init - vc_cma_chunks = %d", vc_cma_chunks);
-+ if (vc_cma_size) {
-+ int rc = platform_device_register(&vc_cma_device);
-+ LOG_DBG("platform_device_register -> %d", rc);
-+ }
-+}
-+
-+void vc_cma_reserve(void)
-+{
-+ /* if vc_cma_size is set, then declare vc CMA area of the same
-+ * size from the end of memory
-+ */
-+ if (vc_cma_size) {
-+ if (dma_declare_contiguous(NULL /*&vc_cma_device.dev*/, vc_cma_size,
-+ vc_cma_base, 0) == 0) {
-+ } else {
-+ LOG_ERR("vc_cma: dma_declare_contiguous(%x,%x) failed",
-+ vc_cma_size, (unsigned int)vc_cma_base);
-+ vc_cma_size = 0;
-+ }
-+ }
-+ vc_cma_chunks = vc_cma_size / VC_CMA_CHUNK_SIZE;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_open
-+*
-+***************************************************************************/
-+
-+static int vc_cma_open(struct inode *inode, struct file *file)
-+{
-+ (void)inode;
-+ (void)file;
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_release
-+*
-+***************************************************************************/
-+
-+static int vc_cma_release(struct inode *inode, struct file *file)
-+{
-+ (void)inode;
-+ (void)file;
-+
-+ vc_cma_set_reserve(0, current->tgid);
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_ioctl
-+*
-+***************************************************************************/
-+
-+static long vc_cma_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ int rc = 0;
-+
-+ (void)cmd;
-+ (void)arg;
-+
-+ switch (cmd) {
-+ case VC_CMA_IOC_RESERVE:
-+ rc = vc_cma_set_reserve((unsigned int)arg, current->tgid);
-+ if (rc >= 0)
-+ rc = 0;
-+ break;
-+ default:
-+ LOG_ERR("vc-cma: Unknown ioctl %x", cmd);
-+ return -ENOTTY;
-+ }
-+
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* File Operations for the driver.
-+*
-+***************************************************************************/
-+
-+static const struct file_operations vc_cma_fops = {
-+ .owner = THIS_MODULE,
-+ .open = vc_cma_open,
-+ .release = vc_cma_release,
-+ .unlocked_ioctl = vc_cma_ioctl,
-+};
-+
-+/****************************************************************************
-+*
-+* vc_cma_proc_open
-+*
-+***************************************************************************/
-+
-+static int vc_cma_show_info(struct seq_file *m, void *v)
-+{
-+ int i;
-+
-+ seq_printf(m, "Videocore CMA:\n");
-+ seq_printf(m, " Base : %08x\n", (unsigned int)vc_cma_base);
-+ seq_printf(m, " Length : %08x\n", vc_cma_size);
-+ seq_printf(m, " Initial : %08x\n", vc_cma_initial);
-+ seq_printf(m, " Chunk size : %08x\n", VC_CMA_CHUNK_SIZE);
-+ seq_printf(m, " Chunks : %4d (%d bytes)\n",
-+ (int)vc_cma_chunks,
-+ (int)(vc_cma_chunks * VC_CMA_CHUNK_SIZE));
-+ seq_printf(m, " Used : %4d (%d bytes)\n",
-+ (int)vc_cma_chunks_used,
-+ (int)(vc_cma_chunks_used * VC_CMA_CHUNK_SIZE));
-+ seq_printf(m, " Reserved : %4d (%d bytes)\n",
-+ (unsigned int)vc_cma_chunks_reserved,
-+ (int)(vc_cma_chunks_reserved * VC_CMA_CHUNK_SIZE));
-+
-+ for (i = 0; i < vc_cma_reserve_count; i++) {
-+ struct vc_cma_reserve_user *user = &vc_cma_reserve_users[i];
-+ seq_printf(m, " PID %5d: %d bytes\n", user->pid,
-+ user->reserve);
-+ }
-+
-+ seq_printf(m, "\n");
-+
-+ return 0;
-+}
-+
-+static int vc_cma_proc_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, vc_cma_show_info, NULL);
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_proc_write
-+*
-+***************************************************************************/
-+
-+static int vc_cma_proc_write(struct file *file,
-+ const char __user *buffer,
-+ size_t size, loff_t *ppos)
-+{
-+ int rc = -EFAULT;
-+ char input_str[20];
-+
-+ memset(input_str, 0, sizeof(input_str));
-+
-+ if (size > sizeof(input_str)) {
-+ LOG_ERR("%s: input string length too long", __func__);
-+ goto out;
-+ }
-+
-+ if (copy_from_user(input_str, buffer, size - 1)) {
-+ LOG_ERR("%s: failed to get input string", __func__);
-+ goto out;
-+ }
-+#define ALLOC_STR "alloc"
-+#define FREE_STR "free"
-+#define DEBUG_STR "debug"
-+#define RESERVE_STR "reserve"
-+ if (strncmp(input_str, ALLOC_STR, strlen(ALLOC_STR)) == 0) {
-+ int size;
-+ char *p = input_str + strlen(ALLOC_STR);
-+
-+ while (*p == ' ')
-+ p++;
-+ size = memparse(p, NULL);
-+ LOG_ERR("/proc/vc-cma: alloc %d", size);
-+ if (size)
-+ send_vc_msg(VC_CMA_MSG_REQUEST_FREE,
-+ size / VC_CMA_CHUNK_SIZE, 0);
-+ else
-+ LOG_ERR("invalid size '%s'", p);
-+ rc = size;
-+ } else if (strncmp(input_str, FREE_STR, strlen(FREE_STR)) == 0) {
-+ int size;
-+ char *p = input_str + strlen(FREE_STR);
-+
-+ while (*p == ' ')
-+ p++;
-+ size = memparse(p, NULL);
-+ LOG_ERR("/proc/vc-cma: free %d", size);
-+ if (size)
-+ send_vc_msg(VC_CMA_MSG_REQUEST_ALLOC,
-+ size / VC_CMA_CHUNK_SIZE, 0);
-+ else
-+ LOG_ERR("invalid size '%s'", p);
-+ rc = size;
-+ } else if (strncmp(input_str, DEBUG_STR, strlen(DEBUG_STR)) == 0) {
-+ char *p = input_str + strlen(DEBUG_STR);
-+ while (*p == ' ')
-+ p++;
-+ if ((strcmp(p, "on") == 0) || (strcmp(p, "1") == 0))
-+ vc_cma_debug = 1;
-+ else if ((strcmp(p, "off") == 0) || (strcmp(p, "0") == 0))
-+ vc_cma_debug = 0;
-+ LOG_ERR("/proc/vc-cma: debug %s", vc_cma_debug ? "on" : "off");
-+ rc = size;
-+ } else if (strncmp(input_str, RESERVE_STR, strlen(RESERVE_STR)) == 0) {
-+ int size;
-+ int reserved;
-+ char *p = input_str + strlen(RESERVE_STR);
-+ while (*p == ' ')
-+ p++;
-+ size = memparse(p, NULL);
-+
-+ reserved = vc_cma_set_reserve(size, current->tgid);
-+ rc = (reserved >= 0) ? size : reserved;
-+ }
-+
-+out:
-+ return rc;
-+}
-+
-+/****************************************************************************
-+*
-+* File Operations for /proc interface.
-+*
-+***************************************************************************/
-+
-+static const struct file_operations vc_cma_proc_fops = {
-+ .open = vc_cma_proc_open,
-+ .read = seq_read,
-+ .write = vc_cma_proc_write,
-+ .llseek = seq_lseek,
-+ .release = single_release
-+};
-+
-+static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid)
-+{
-+ struct vc_cma_reserve_user *user = NULL;
-+ int delta = 0;
-+ int i;
-+
-+ if (down_interruptible(&vc_cma_reserve_mutex))
-+ return -ERESTARTSYS;
-+
-+ for (i = 0; i < vc_cma_reserve_count; i++) {
-+ if (pid == vc_cma_reserve_users[i].pid) {
-+ user = &vc_cma_reserve_users[i];
-+ delta = reserve - user->reserve;
-+ if (reserve)
-+ user->reserve = reserve;
-+ else {
-+ /* Remove this entry by copying downwards */
-+ while ((i + 1) < vc_cma_reserve_count) {
-+ user[0].pid = user[1].pid;
-+ user[0].reserve = user[1].reserve;
-+ user++;
-+ i++;
-+ }
-+ vc_cma_reserve_count--;
-+ user = NULL;
-+ }
-+ break;
-+ }
-+ }
-+
-+ if (reserve && !user) {
-+ if (vc_cma_reserve_count == VC_CMA_RESERVE_COUNT_MAX) {
-+ LOG_ERR("vc-cma: Too many reservations - "
-+ "increase CMA_RESERVE_COUNT_MAX");
-+ up(&vc_cma_reserve_mutex);
-+ return -EBUSY;
-+ }
-+ user = &vc_cma_reserve_users[vc_cma_reserve_count];
-+ user->pid = pid;
-+ user->reserve = reserve;
-+ delta = reserve;
-+ vc_cma_reserve_count++;
-+ }
-+
-+ vc_cma_reserve_total += delta;
-+
-+ send_vc_msg(VC_CMA_MSG_RESERVE,
-+ vc_cma_reserve_total & 0xffff, vc_cma_reserve_total >> 16);
-+
-+ send_worker_msg((VCHIQ_HEADER_T *) VC_CMA_MSG_UPDATE_RESERVE);
-+
-+ LOG_DBG("/proc/vc-cma: reserve %d (PID %d) - total %u",
-+ reserve, pid, vc_cma_reserve_total);
-+
-+ up(&vc_cma_reserve_mutex);
-+
-+ return vc_cma_reserve_total;
-+}
-+
-+static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T * header,
-+ VCHIQ_SERVICE_HANDLE_T service,
-+ void *bulk_userdata)
-+{
-+ switch (reason) {
-+ case VCHIQ_MESSAGE_AVAILABLE:
-+ if (!send_worker_msg(header))
-+ return VCHIQ_RETRY;
-+ break;
-+ case VCHIQ_SERVICE_CLOSED:
-+ LOG_DBG("CMA service closed");
-+ break;
-+ default:
-+ LOG_ERR("Unexpected CMA callback reason %d", reason);
-+ break;
-+ }
-+ return VCHIQ_SUCCESS;
-+}
-+
-+static void send_vc_msg(unsigned short type,
-+ unsigned short param1, unsigned short param2)
-+{
-+ unsigned short msg[] = { type, param1, param2 };
-+ VCHIQ_ELEMENT_T elem = { &msg, sizeof(msg) };
-+ VCHIQ_STATUS_T ret;
-+ vchiq_use_service(cma_service);
-+ ret = vchiq_queue_message(cma_service, &elem, 1);
-+ vchiq_release_service(cma_service);
-+ if (ret != VCHIQ_SUCCESS)
-+ LOG_ERR("vchiq_queue_message returned %x", ret);
-+}
-+
-+static bool send_worker_msg(VCHIQ_HEADER_T * msg)
-+{
-+ if (down_interruptible(&vc_cma_worker_queue_push_mutex))
-+ return false;
-+ vchiu_queue_push(&cma_msg_queue, msg);
-+ up(&vc_cma_worker_queue_push_mutex);
-+ return true;
-+}
-+
-+static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply)
-+{
-+ int i;
-+ for (i = 0; i < num_chunks; i++) {
-+ struct page *chunk;
-+ unsigned int chunk_num;
-+ uint8_t *chunk_addr;
-+ size_t chunk_size = PAGES_PER_CHUNK << PAGE_SHIFT;
-+
-+ chunk = dma_alloc_from_contiguous(NULL /*&vc_cma_device.dev*/,
-+ PAGES_PER_CHUNK,
-+ VC_CMA_CHUNK_ORDER);
-+ if (!chunk)
-+ break;
-+
-+ chunk_addr = page_address(chunk);
-+ dmac_flush_range(chunk_addr, chunk_addr + chunk_size);
-+ outer_inv_range(__pa(chunk_addr), __pa(chunk_addr) +
-+ chunk_size);
-+
-+ chunk_num =
-+ (page_to_phys(chunk) - vc_cma_base) / VC_CMA_CHUNK_SIZE;
-+ BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
-+ VC_CMA_CHUNK_SIZE) != 0);
-+ if (chunk_num >= vc_cma_chunks) {
-+ LOG_ERR("%s: ===============================",
-+ __func__);
-+ LOG_ERR("%s: chunk phys %x, vc_cma %x-%x - "
-+ "bad SPARSEMEM configuration?",
-+ __func__, (unsigned int)page_to_phys(chunk),
-+ vc_cma_base, vc_cma_base + vc_cma_size - 1);
-+ LOG_ERR("%s: dev->cma_area = %p\n", __func__,
-+ vc_cma_device.dev.cma_area);
-+ LOG_ERR("%s: ===============================",
-+ __func__);
-+ break;
-+ }
-+ reply->params[i] = chunk_num;
-+ vc_cma_chunks_used++;
-+ }
-+
-+ if (i < num_chunks) {
-+ LOG_ERR("%s: dma_alloc_from_contiguous failed "
-+ "for %x bytes (alloc %d of %d, %d free)",
-+ __func__, VC_CMA_CHUNK_SIZE, i,
-+ num_chunks, vc_cma_chunks - vc_cma_chunks_used);
-+ num_chunks = i;
-+ }
-+
-+ LOG_DBG("CMA allocated %d chunks -> %d used",
-+ num_chunks, vc_cma_chunks_used);
-+ reply->type = VC_CMA_MSG_ALLOCATED;
-+
-+ {
-+ VCHIQ_ELEMENT_T elem = {
-+ reply,
-+ offsetof(struct cma_msg, params[0]) +
-+ num_chunks * sizeof(reply->params[0])
-+ };
-+ VCHIQ_STATUS_T ret;
-+ vchiq_use_service(cma_service);
-+ ret = vchiq_queue_message(cma_service, &elem, 1);
-+ vchiq_release_service(cma_service);
-+ if (ret != VCHIQ_SUCCESS)
-+ LOG_ERR("vchiq_queue_message return " "%x", ret);
-+ }
-+
-+ return num_chunks;
-+}
-+
-+static int cma_worker_proc(void *param)
-+{
-+ static struct cma_msg reply;
-+ (void)param;
-+
-+ while (1) {
-+ VCHIQ_HEADER_T *msg;
-+ static struct cma_msg msg_copy;
-+ struct cma_msg *cma_msg = &msg_copy;
-+ int type, msg_size;
-+
-+ msg = vchiu_queue_pop(&cma_msg_queue);
-+ if ((unsigned int)msg >= VC_CMA_MSG_MAX) {
-+ msg_size = msg->size;
-+ memcpy(&msg_copy, msg->data, msg_size);
-+ type = cma_msg->type;
-+ vchiq_release_message(cma_service, msg);
-+ } else {
-+ msg_size = 0;
-+ type = (int)msg;
-+ if (type == VC_CMA_MSG_QUIT)
-+ break;
-+ else if (type == VC_CMA_MSG_UPDATE_RESERVE) {
-+ msg = NULL;
-+ cma_msg = NULL;
-+ } else {
-+ BUG();
-+ continue;
-+ }
-+ }
-+
-+ switch (type) {
-+ case VC_CMA_MSG_ALLOC:{
-+ int num_chunks, free_chunks;
-+ num_chunks = cma_msg->params[0];
-+ free_chunks =
-+ vc_cma_chunks - vc_cma_chunks_used;
-+ LOG_DBG("CMA_MSG_ALLOC(%d chunks)", num_chunks);
-+ if (num_chunks > VC_CMA_MAX_PARAMS_PER_MSG) {
-+ LOG_ERR
-+ ("CMA_MSG_ALLOC - chunk count (%d) "
-+ "exceeds VC_CMA_MAX_PARAMS_PER_MSG (%d)",
-+ num_chunks,
-+ VC_CMA_MAX_PARAMS_PER_MSG);
-+ num_chunks = VC_CMA_MAX_PARAMS_PER_MSG;
-+ }
-+
-+ if (num_chunks > free_chunks) {
-+ LOG_ERR
-+ ("CMA_MSG_ALLOC - chunk count (%d) "
-+ "exceeds free chunks (%d)",
-+ num_chunks, free_chunks);
-+ num_chunks = free_chunks;
-+ }
-+
-+ vc_cma_alloc_chunks(num_chunks, &reply);
-+ }
-+ break;
-+
-+ case VC_CMA_MSG_FREE:{
-+ int chunk_count =
-+ (msg_size -
-+ offsetof(struct cma_msg,
-+ params)) /
-+ sizeof(cma_msg->params[0]);
-+ int i;
-+ BUG_ON(chunk_count <= 0);
-+
-+ LOG_DBG("CMA_MSG_FREE(%d chunks - %x, ...)",
-+ chunk_count, cma_msg->params[0]);
-+ for (i = 0; i < chunk_count; i++) {
-+ int chunk_num = cma_msg->params[i];
-+ struct page *page = vc_cma_base_page +
-+ chunk_num * PAGES_PER_CHUNK;
-+ if (chunk_num >= vc_cma_chunks) {
-+ LOG_ERR
-+ ("CMA_MSG_FREE - chunk %d of %d"
-+ " (value %x) exceeds maximum "
-+ "(%x)", i, chunk_count,
-+ chunk_num,
-+ vc_cma_chunks - 1);
-+ break;
-+ }
-+
-+ if (!dma_release_from_contiguous
-+ (NULL /*&vc_cma_device.dev*/, page,
-+ PAGES_PER_CHUNK)) {
-+ LOG_ERR
-+ ("CMA_MSG_FREE - failed to "
-+ "release chunk %d (phys %x, "
-+ "page %x)", chunk_num,
-+ page_to_phys(page),
-+ (unsigned int)page);
-+ }
-+ vc_cma_chunks_used--;
-+ }
-+ LOG_DBG("CMA released %d chunks -> %d used",
-+ i, vc_cma_chunks_used);
-+ }
-+ break;
-+
-+ case VC_CMA_MSG_UPDATE_RESERVE:{
-+ int chunks_needed =
-+ ((vc_cma_reserve_total + VC_CMA_CHUNK_SIZE -
-+ 1)
-+ / VC_CMA_CHUNK_SIZE) -
-+ vc_cma_chunks_reserved;
-+
-+ LOG_DBG
-+ ("CMA_MSG_UPDATE_RESERVE(%d chunks needed)",
-+ chunks_needed);
-+
-+ /* Cap the reservations to what is available */
-+ if (chunks_needed > 0) {
-+ if (chunks_needed >
-+ (vc_cma_chunks -
-+ vc_cma_chunks_used))
-+ chunks_needed =
-+ (vc_cma_chunks -
-+ vc_cma_chunks_used);
-+
-+ chunks_needed =
-+ vc_cma_alloc_chunks(chunks_needed,
-+ &reply);
-+ }
-+
-+ LOG_DBG
-+ ("CMA_MSG_UPDATE_RESERVE(%d chunks allocated)",
-+ chunks_needed);
-+ vc_cma_chunks_reserved += chunks_needed;
-+ }
-+ break;
-+
-+ default:
-+ LOG_ERR("unexpected msg type %d", type);
-+ break;
-+ }
-+ }
-+
-+ LOG_DBG("quitting...");
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_connected_init
-+*
-+* This function is called once the videocore has been connected.
-+*
-+***************************************************************************/
-+
-+static void vc_cma_connected_init(void)
-+{
-+ VCHIQ_SERVICE_PARAMS_T service_params;
-+
-+ LOG_DBG("vc_cma_connected_init");
-+
-+ if (!vchiu_queue_init(&cma_msg_queue, 16)) {
-+ LOG_ERR("could not create CMA msg queue");
-+ goto fail_queue;
-+ }
-+
-+ if (vchiq_initialise(&cma_instance) != VCHIQ_SUCCESS)
-+ goto fail_vchiq_init;
-+
-+ vchiq_connect(cma_instance);
-+
-+ service_params.fourcc = VC_CMA_FOURCC;
-+ service_params.callback = cma_service_callback;
-+ service_params.userdata = NULL;
-+ service_params.version = VC_CMA_VERSION;
-+ service_params.version_min = VC_CMA_VERSION;
-+
-+ if (vchiq_open_service(cma_instance, &service_params,
-+ &cma_service) != VCHIQ_SUCCESS) {
-+ LOG_ERR("failed to open service - already in use?");
-+ goto fail_vchiq_open;
-+ }
-+
-+ vchiq_release_service(cma_service);
-+
-+ cma_worker = kthread_create(cma_worker_proc, NULL, "cma_worker");
-+ if (!cma_worker) {
-+ LOG_ERR("could not create CMA worker thread");
-+ goto fail_worker;
-+ }
-+ set_user_nice(cma_worker, -20);
-+ wake_up_process(cma_worker);
-+
-+ return;
-+
-+fail_worker:
-+ vchiq_close_service(cma_service);
-+fail_vchiq_open:
-+ vchiq_shutdown(cma_instance);
-+fail_vchiq_init:
-+ vchiu_queue_delete(&cma_msg_queue);
-+fail_queue:
-+ return;
-+}
-+
-+void
-+loud_error_header(void)
-+{
-+ if (in_loud_error)
-+ return;
-+
-+ LOG_ERR("============================================================"
-+ "================");
-+ LOG_ERR("============================================================"
-+ "================");
-+ LOG_ERR("=====");
-+
-+ in_loud_error = 1;
-+}
-+
-+void
-+loud_error_footer(void)
-+{
-+ if (!in_loud_error)
-+ return;
-+
-+ LOG_ERR("=====");
-+ LOG_ERR("============================================================"
-+ "================");
-+ LOG_ERR("============================================================"
-+ "================");
-+
-+ in_loud_error = 0;
-+}
-+
-+#if 1
-+static int check_cma_config(void) { return 1; }
-+#else
-+static int
-+read_vc_debug_var(VC_MEM_ACCESS_HANDLE_T handle,
-+ const char *symbol,
-+ void *buf, size_t bufsize)
-+{
-+ VC_MEM_ADDR_T vcMemAddr;
-+ size_t vcMemSize;
-+ uint8_t *mapAddr;
-+ off_t vcMapAddr;
-+
-+ if (!LookupVideoCoreSymbol(handle, symbol,
-+ &vcMemAddr,
-+ &vcMemSize)) {
-+ loud_error_header();
-+ loud_error(
-+ "failed to find VC symbol \"%s\".",
-+ symbol);
-+ loud_error_footer();
-+ return 0;
-+ }
-+
-+ if (vcMemSize != bufsize) {
-+ loud_error_header();
-+ loud_error(
-+ "VC symbol \"%s\" is the wrong size.",
-+ symbol);
-+ loud_error_footer();
-+ return 0;
-+ }
-+
-+ vcMapAddr = (off_t)vcMemAddr & VC_MEM_TO_ARM_ADDR_MASK;
-+ vcMapAddr += mm_vc_mem_phys_addr;
-+ mapAddr = ioremap_nocache(vcMapAddr, vcMemSize);
-+ if (mapAddr == 0) {
-+ loud_error_header();
-+ loud_error(
-+ "failed to ioremap \"%s\" @ 0x%x "
-+ "(phys: 0x%x, size: %u).",
-+ symbol,
-+ (unsigned int)vcMapAddr,
-+ (unsigned int)vcMemAddr,
-+ (unsigned int)vcMemSize);
-+ loud_error_footer();
-+ return 0;
-+ }
-+
-+ memcpy(buf, mapAddr, bufsize);
-+ iounmap(mapAddr);
-+
-+ return 1;
-+}
-+
-+
-+static int
-+check_cma_config(void)
-+{
-+ VC_MEM_ACCESS_HANDLE_T mem_hndl;
-+ VC_MEM_ADDR_T mempool_start;
-+ VC_MEM_ADDR_T mempool_end;
-+ VC_MEM_ADDR_T mempool_offline_start;
-+ VC_MEM_ADDR_T mempool_offline_end;
-+ VC_MEM_ADDR_T cam_alloc_base;
-+ VC_MEM_ADDR_T cam_alloc_size;
-+ VC_MEM_ADDR_T cam_alloc_end;
-+ int success = 0;
-+
-+ if (OpenVideoCoreMemory(&mem_hndl) != 0)
-+ goto out;
-+
-+ /* Read the relevant VideoCore variables */
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_START",
-+ &mempool_start,
-+ sizeof(mempool_start)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_END",
-+ &mempool_end,
-+ sizeof(mempool_end)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_START",
-+ &mempool_offline_start,
-+ sizeof(mempool_offline_start)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_END",
-+ &mempool_offline_end,
-+ sizeof(mempool_offline_end)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "cam_alloc_base",
-+ &cam_alloc_base,
-+ sizeof(cam_alloc_base)))
-+ goto close;
-+
-+ if (!read_vc_debug_var(mem_hndl, "cam_alloc_size",
-+ &cam_alloc_size,
-+ sizeof(cam_alloc_size)))
-+ goto close;
-+
-+ cam_alloc_end = cam_alloc_base + cam_alloc_size;
-+
-+ success = 1;
-+
-+ /* Now the sanity checks */
-+ if (!mempool_offline_start)
-+ mempool_offline_start = mempool_start;
-+ if (!mempool_offline_end)
-+ mempool_offline_end = mempool_end;
-+
-+ if (VCADDR_TO_PHYSADDR(mempool_offline_start) != vc_cma_base) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_START(%x -> %lx) doesn't match "
-+ "vc_cma_base(%x)",
-+ mempool_offline_start,
-+ VCADDR_TO_PHYSADDR(mempool_offline_start),
-+ vc_cma_base);
-+ success = 0;
-+ }
-+
-+ if (VCADDR_TO_PHYSADDR(mempool_offline_end) !=
-+ (vc_cma_base + vc_cma_size)) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_END(%x -> %lx) doesn't match "
-+ "vc_cma_base(%x) + vc_cma_size(%x) = %x",
-+ mempool_offline_start,
-+ VCADDR_TO_PHYSADDR(mempool_offline_end),
-+ vc_cma_base, vc_cma_size, vc_cma_base + vc_cma_size);
-+ success = 0;
-+ }
-+
-+ if (mempool_end < mempool_start) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_END(%x) must not be before "
-+ "__MEMPOOL_START(%x)",
-+ mempool_end,
-+ mempool_start);
-+ success = 0;
-+ }
-+
-+ if (mempool_offline_end < mempool_offline_start) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_END(%x) must not be before "
-+ "__MEMPOOL_OFFLINE_START(%x)",
-+ mempool_offline_end,
-+ mempool_offline_start);
-+ success = 0;
-+ }
-+
-+ if (mempool_offline_start < mempool_start) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_START(%x) must not be before "
-+ "__MEMPOOL_START(%x)",
-+ mempool_offline_start,
-+ mempool_start);
-+ success = 0;
-+ }
-+
-+ if (mempool_offline_end > mempool_end) {
-+ loud_error_header();
-+ loud_error(
-+ "__MEMPOOL_OFFLINE_END(%x) must not be after "
-+ "__MEMPOOL_END(%x)",
-+ mempool_offline_end,
-+ mempool_end);
-+ success = 0;
-+ }
-+
-+ if ((cam_alloc_base < mempool_end) &&
-+ (cam_alloc_end > mempool_start)) {
-+ loud_error_header();
-+ loud_error(
-+ "cam_alloc pool(%x-%x) overlaps "
-+ "mempool(%x-%x)",
-+ cam_alloc_base, cam_alloc_end,
-+ mempool_start, mempool_end);
-+ success = 0;
-+ }
-+
-+ loud_error_footer();
-+
-+close:
-+ CloseVideoCoreMemory(mem_hndl);
-+
-+out:
-+ return success;
-+}
-+#endif
-+
-+static int vc_cma_init(void)
-+{
-+ int rc = -EFAULT;
-+ struct device *dev;
-+
-+ if (!check_cma_config())
-+ goto out_release;
-+
-+ printk(KERN_INFO "vc-cma: Videocore CMA driver\n");
-+ printk(KERN_INFO "vc-cma: vc_cma_base = 0x%08x\n", vc_cma_base);
-+ printk(KERN_INFO "vc-cma: vc_cma_size = 0x%08x (%u MiB)\n",
-+ vc_cma_size, vc_cma_size / (1024 * 1024));
-+ printk(KERN_INFO "vc-cma: vc_cma_initial = 0x%08x (%u MiB)\n",
-+ vc_cma_initial, vc_cma_initial / (1024 * 1024));
-+
-+ vc_cma_base_page = phys_to_page(vc_cma_base);
-+
-+ if (vc_cma_chunks) {
-+ int chunks_needed = vc_cma_initial / VC_CMA_CHUNK_SIZE;
-+
-+ for (vc_cma_chunks_used = 0;
-+ vc_cma_chunks_used < chunks_needed; vc_cma_chunks_used++) {
-+ struct page *chunk;
-+ chunk = dma_alloc_from_contiguous(NULL /*&vc_cma_device.dev*/,
-+ PAGES_PER_CHUNK,
-+ VC_CMA_CHUNK_ORDER);
-+ if (!chunk)
-+ break;
-+ BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
-+ VC_CMA_CHUNK_SIZE) != 0);
-+ }
-+ if (vc_cma_chunks_used != chunks_needed) {
-+ LOG_ERR("%s: dma_alloc_from_contiguous failed (%d "
-+ "bytes, allocation %d of %d)",
-+ __func__, VC_CMA_CHUNK_SIZE,
-+ vc_cma_chunks_used, chunks_needed);
-+ goto out_release;
-+ }
-+
-+ vchiq_add_connected_callback(vc_cma_connected_init);
-+ }
-+
-+ rc = alloc_chrdev_region(&vc_cma_devnum, 0, 1, DRIVER_NAME);
-+ if (rc < 0) {
-+ LOG_ERR("%s: alloc_chrdev_region failed (rc=%d)", __func__, rc);
-+ goto out_release;
-+ }
-+
-+ cdev_init(&vc_cma_cdev, &vc_cma_fops);
-+ rc = cdev_add(&vc_cma_cdev, vc_cma_devnum, 1);
-+ if (rc != 0) {
-+ LOG_ERR("%s: cdev_add failed (rc=%d)", __func__, rc);
-+ goto out_unregister;
-+ }
-+
-+ vc_cma_class = class_create(THIS_MODULE, DRIVER_NAME);
-+ if (IS_ERR(vc_cma_class)) {
-+ rc = PTR_ERR(vc_cma_class);
-+ LOG_ERR("%s: class_create failed (rc=%d)", __func__, rc);
-+ goto out_cdev_del;
-+ }
-+
-+ dev = device_create(vc_cma_class, NULL, vc_cma_devnum, NULL,
-+ DRIVER_NAME);
-+ if (IS_ERR(dev)) {
-+ rc = PTR_ERR(dev);
-+ LOG_ERR("%s: device_create failed (rc=%d)", __func__, rc);
-+ goto out_class_destroy;
-+ }
-+
-+ vc_cma_proc_entry = proc_create(DRIVER_NAME, 0444, NULL, &vc_cma_proc_fops);
-+ if (vc_cma_proc_entry == NULL) {
-+ rc = -EFAULT;
-+ LOG_ERR("%s: proc_create failed", __func__);
-+ goto out_device_destroy;
-+ }
-+
-+ vc_cma_inited = 1;
-+ return 0;
-+
-+out_device_destroy:
-+ device_destroy(vc_cma_class, vc_cma_devnum);
-+
-+out_class_destroy:
-+ class_destroy(vc_cma_class);
-+ vc_cma_class = NULL;
-+
-+out_cdev_del:
-+ cdev_del(&vc_cma_cdev);
-+
-+out_unregister:
-+ unregister_chrdev_region(vc_cma_devnum, 1);
-+
-+out_release:
-+ /* It is tempting to try to clean up by calling
-+ dma_release_from_contiguous for all allocated chunks, but it isn't
-+ a very safe thing to do. If vc_cma_initial is non-zero it is because
-+ VideoCore is already using that memory, so giving it back to Linux
-+ is likely to be fatal.
-+ */
-+ return -1;
-+}
-+
-+/****************************************************************************
-+*
-+* vc_cma_exit
-+*
-+***************************************************************************/
-+
-+static void __exit vc_cma_exit(void)
-+{
-+ LOG_DBG("%s: called", __func__);
-+
-+ if (vc_cma_inited) {
-+ remove_proc_entry(DRIVER_NAME, NULL);
-+ device_destroy(vc_cma_class, vc_cma_devnum);
-+ class_destroy(vc_cma_class);
-+ cdev_del(&vc_cma_cdev);
-+ unregister_chrdev_region(vc_cma_devnum, 1);
-+ }
-+}
-+
-+module_init(vc_cma_init);
-+module_exit(vc_cma_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Broadcom Corporation");
-diff -Nur linux-3.11.10.orig/drivers/char/hw_random/bcm2708-rng.c linux-3.11.10/drivers/char/hw_random/bcm2708-rng.c
---- linux-3.11.10.orig/drivers/char/hw_random/bcm2708-rng.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/char/hw_random/bcm2708-rng.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,117 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/hw_random.h>
-+#include <linux/printk.h>
-+
-+#include <asm/io.h>
-+#include <mach/hardware.h>
-+#include <mach/platform.h>
-+
-+#define RNG_CTRL (0x0)
-+#define RNG_STATUS (0x4)
-+#define RNG_DATA (0x8)
-+#define RNG_FF_THRESHOLD (0xc)
-+
-+/* enable rng */
-+#define RNG_RBGEN 0x1
-+/* double speed, less random mode */
-+#define RNG_RBG2X 0x2
-+
-+/* the initial numbers generated are "less random" so will be discarded */
-+#define RNG_WARMUP_COUNT 0x40000
-+
-+static int bcm2708_rng_data_read(struct hwrng *rng, u32 *buffer)
-+{
-+ void __iomem *rng_base = (void __iomem *)rng->priv;
-+ unsigned words;
-+ /* wait for a random number to be in fifo */
-+ do {
-+ words = __raw_readl(rng_base + RNG_STATUS)>>24;
-+ }
-+ while (words == 0);
-+ /* read the random number */
-+ *buffer = __raw_readl(rng_base + RNG_DATA);
-+ return 4;
-+}
-+
-+static struct hwrng bcm2708_rng_ops = {
-+ .name = "bcm2708",
-+ .data_read = bcm2708_rng_data_read,
-+};
-+
-+static int __init bcm2708_rng_init(void)
-+{
-+ void __iomem *rng_base;
-+ int err;
-+
-+ /* map peripheral */
-+ rng_base = ioremap(RNG_BASE, 0x10);
-+ pr_info("bcm2708_rng_init=%p\n", rng_base);
-+ if (!rng_base) {
-+ pr_err("bcm2708_rng_init failed to ioremap\n");
-+ return -ENOMEM;
-+ }
-+ bcm2708_rng_ops.priv = (unsigned long)rng_base;
-+ /* register driver */
-+ err = hwrng_register(&bcm2708_rng_ops);
-+ if (err) {
-+ pr_err("bcm2708_rng_init hwrng_register()=%d\n", err);
-+ iounmap(rng_base);
-+ } else {
-+ /* set warm-up count & enable */
-+ __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
-+ __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
-+ }
-+ return err;
-+}
-+
-+static void __exit bcm2708_rng_exit(void)
-+{
-+ void __iomem *rng_base = (void __iomem *)bcm2708_rng_ops.priv;
-+ pr_info("bcm2708_rng_exit\n");
-+ /* disable rng hardware */
-+ __raw_writel(0, rng_base + RNG_CTRL);
-+ /* unregister driver */
-+ hwrng_unregister(&bcm2708_rng_ops);
-+ iounmap(rng_base);
-+}
-+
-+module_init(bcm2708_rng_init);
-+module_exit(bcm2708_rng_exit);
-+
-+MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver");
-+MODULE_LICENSE("GPL and additional rights");
-diff -Nur linux-3.11.10.orig/drivers/char/hw_random/Kconfig linux-3.11.10/drivers/char/hw_random/Kconfig
---- linux-3.11.10.orig/drivers/char/hw_random/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/char/hw_random/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -314,3 +314,14 @@
- module will be called tpm-rng.
-
- If unsure, say Y.
-+
-+config HW_RANDOM_BCM2708
-+ tristate "BCM2708 generic true random number generator support"
-+ depends on HW_RANDOM && ARCH_BCM2708
-+ ---help---
-+ This driver provides the kernel-side support for the BCM2708 hardware.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called bcm2708-rng.
-+
-+ If unsure, say N.
-diff -Nur linux-3.11.10.orig/drivers/char/hw_random/Makefile linux-3.11.10/drivers/char/hw_random/Makefile
---- linux-3.11.10.orig/drivers/char/hw_random/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/char/hw_random/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -27,3 +27,4 @@
- obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
- obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
- obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
-+obj-$(CONFIG_HW_RANDOM_BCM2708) += bcm2708-rng.o
-diff -Nur linux-3.11.10.orig/drivers/char/Kconfig linux-3.11.10/drivers/char/Kconfig
---- linux-3.11.10.orig/drivers/char/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/char/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -574,6 +574,8 @@
-
- source "drivers/s390/char/Kconfig"
-
-+source "drivers/char/broadcom/Kconfig"
-+
- config MSM_SMD_PKT
- bool "Enable device interface for some SMD packet ports"
- default n
-diff -Nur linux-3.11.10.orig/drivers/char/Makefile linux-3.11.10/drivers/char/Makefile
---- linux-3.11.10.orig/drivers/char/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/char/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -62,3 +62,5 @@
- js-rtc-y = rtc.o
-
- obj-$(CONFIG_TILE_SROM) += tile-srom.o
-+
-+obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/
-diff -Nur linux-3.11.10.orig/drivers/cpufreq/bcm2835-cpufreq.c linux-3.11.10/drivers/cpufreq/bcm2835-cpufreq.c
---- linux-3.11.10.orig/drivers/cpufreq/bcm2835-cpufreq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/cpufreq/bcm2835-cpufreq.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,238 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+/*****************************************************************************
-+* FILENAME: bcm2835-cpufreq.h
-+* DESCRIPTION: This driver dynamically manages the CPU Frequency of the ARM
-+* processor. Messages are sent to Videocore either setting or requesting the
-+* frequency of the ARM in order to match an appropiate frequency to the current
-+* usage of the processor. The policy which selects the frequency to use is
-+* defined in the kernel .config file, but can be changed during runtime.
-+*****************************************************************************/
-+
-+/* ---------- INCLUDES ---------- */
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/cpufreq.h>
-+#include <mach/vcio.h>
-+
-+/* ---------- DEFINES ---------- */
-+/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
-+#define MODULE_NAME "bcm2835-cpufreq"
-+
-+#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
-+
-+/* debug printk macros */
-+#ifdef CPUFREQ_DEBUG_ENABLE
-+#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
-+#else
-+#define print_debug(fmt,...)
-+#endif
-+#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
-+#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
-+
-+/* tag part of the message */
-+struct vc_msg_tag {
-+ uint32_t tag_id; /* the message id */
-+ uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */
-+ uint32_t data_size; /* amount of data being sent or received */
-+ uint32_t dev_id; /* the ID of the clock/voltage to get or set */
-+ uint32_t val; /* the value (e.g. rate (in Hz)) to set */
-+};
-+
-+/* message structure to be sent to videocore */
-+struct vc_msg {
-+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
-+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
-+ struct vc_msg_tag tag; /* the tag structure above to make */
-+ uint32_t end_tag; /* an end identifier, should be set to NULL */
-+};
-+
-+/* ---------- GLOBALS ---------- */
-+static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
-+
-+/*
-+ ===============================================
-+ clk_rate either gets or sets the clock rates.
-+ ===============================================
-+*/
-+static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
-+{
-+ int s, actual_rate=0;
-+ struct vc_msg msg;
-+
-+ /* wipe all previous message data */
-+ memset(&msg, 0, sizeof msg);
-+
-+ msg.msg_size = sizeof msg;
-+
-+ msg.tag.tag_id = VCMSG_SET_CLOCK_RATE;
-+ msg.tag.buffer_size = 8;
-+ msg.tag.data_size = 8; /* we're sending the clock ID and the new rates which is a total of 2 words */
-+ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
-+ msg.tag.val = arm_rate * 1000;
-+
-+ /* send the message */
-+ s = bcm_mailbox_property(&msg, sizeof msg);
-+
-+ /* check if it was all ok and return the rate in KHz */
-+ if (s == 0 && (msg.request_code & 0x80000000))
-+ actual_rate = msg.tag.val/1000;
-+
-+ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, actual_rate);
-+ return actual_rate;
-+}
-+
-+static uint32_t bcm2835_cpufreq_get_clock(int tag)
-+{
-+ int s;
-+ int arm_rate = 0;
-+ struct vc_msg msg;
-+
-+ /* wipe all previous message data */
-+ memset(&msg, 0, sizeof msg);
-+
-+ msg.msg_size = sizeof msg;
-+ msg.tag.tag_id = tag;
-+ msg.tag.buffer_size = 8;
-+ msg.tag.data_size = 4; /* we're just sending the clock ID which is one word long */
-+ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
-+
-+ /* send the message */
-+ s = bcm_mailbox_property(&msg, sizeof msg);
-+
-+ /* check if it was all ok and return the rate in KHz */
-+ if (s == 0 && (msg.request_code & 0x80000000))
-+ arm_rate = msg.tag.val/1000;
-+
-+ print_debug("%s frequency = %d\n",
-+ tag == VCMSG_GET_CLOCK_RATE ? "Current":
-+ tag == VCMSG_GET_MIN_CLOCK ? "Min":
-+ tag == VCMSG_GET_MAX_CLOCK ? "Max":
-+ "Unexpected", arm_rate);
-+
-+ return arm_rate;
-+}
-+
-+/*
-+ ====================================================
-+ Module Initialisation registers the cpufreq driver
-+ ====================================================
-+*/
-+static int __init bcm2835_cpufreq_module_init(void)
-+{
-+ print_debug("IN\n");
-+ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
-+}
-+
-+/*
-+ =============
-+ Module exit
-+ =============
-+*/
-+static void __exit bcm2835_cpufreq_module_exit(void)
-+{
-+ print_debug("IN\n");
-+ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
-+ return;
-+}
-+
-+/*
-+ ==============================================================
-+ Initialisation function sets up the CPU policy for first use
-+ ==============================================================
-+*/
-+static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
-+{
-+ /* measured value of how long it takes to change frequency */
-+ policy->cpuinfo.transition_latency = 355000; /* ns */
-+
-+ /* now find out what the maximum and minimum frequencies are */
-+ policy->min = policy->cpuinfo.min_freq = bcm2835_cpufreq_get_clock(VCMSG_GET_MIN_CLOCK);
-+ policy->max = policy->cpuinfo.max_freq = bcm2835_cpufreq_get_clock(VCMSG_GET_MAX_CLOCK);
-+ policy->cur = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
-+
-+ print_info("min=%d max=%d cur=%d\n", policy->min, policy->max, policy->cur);
-+ return 0;
-+}
-+
-+/*
-+ =================================================================================
-+ Target function chooses the most appropriate frequency from the table to enable
-+ =================================================================================
-+*/
-+
-+static int bcm2835_cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
-+{
-+ unsigned int target = target_freq;
-+ unsigned int cur = policy->cur;
-+ print_debug("%s: min=%d max=%d cur=%d target=%d\n",policy->governor->name,policy->min,policy->max,policy->cur,target_freq);
-+
-+ /* if we are above min and using ondemand, then just use max */
-+ if (strcmp("ondemand", policy->governor->name)==0 && target > policy->min)
-+ target = policy->max;
-+ /* if the frequency is the same, just quit */
-+ if (target == policy->cur)
-+ return 0;
-+
-+ /* otherwise were good to set the clock frequency */
-+ policy->cur = bcm2835_cpufreq_set_clock(policy->cur, target);
-+
-+ if (!policy->cur)
-+ {
-+ print_err("Error occurred setting a new frequency (%d)!\n", target);
-+ policy->cur = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
-+ return -EINVAL;
-+ }
-+ print_debug("Freq %d->%d (min=%d max=%d target=%d request=%d)\n", cur, policy->cur, policy->min, policy->max, target_freq, target);
-+ return 0;
-+}
-+
-+static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
-+{
-+ unsigned int actual_rate = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
-+ print_debug("cpu=%d\n", actual_rate);
-+ return actual_rate;
-+}
-+
-+/*
-+ =================================================================================
-+ Verify ensures that when a policy is changed, it is suitable for the CPU to use
-+ =================================================================================
-+*/
-+
-+static int bcm2835_cpufreq_driver_verify(struct cpufreq_policy *policy)
-+{
-+ print_info("switching to governor %s\n", policy->governor->name);
-+ return 0;
-+}
-+
-+
-+/* the CPUFreq driver */
-+static struct cpufreq_driver bcm2835_cpufreq_driver = {
-+ .name = "BCM2835 CPUFreq",
-+ .owner = THIS_MODULE,
-+ .init = bcm2835_cpufreq_driver_init,
-+ .verify = bcm2835_cpufreq_driver_verify,
-+ .target = bcm2835_cpufreq_driver_target,
-+ .get = bcm2835_cpufreq_driver_get
-+};
-+
-+MODULE_AUTHOR("Dorian Peake and Dom Cobley");
-+MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip");
-+MODULE_LICENSE("GPL");
-+
-+module_init(bcm2835_cpufreq_module_init);
-+module_exit(bcm2835_cpufreq_module_exit);
-diff -Nur linux-3.11.10.orig/drivers/cpufreq/Kconfig.arm linux-3.11.10/drivers/cpufreq/Kconfig.arm
---- linux-3.11.10.orig/drivers/cpufreq/Kconfig.arm 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/cpufreq/Kconfig.arm 2014-02-07 19:57:28.000000000 +0100
-@@ -216,6 +216,14 @@
- help
- This adds the CPUFreq driver support for SPEAr SOCs.
-
-+config ARM_BCM2835_CPUFREQ
-+ bool "BCM2835 Driver"
-+ default y
-+ help
-+ This adds the CPUFreq driver for BCM2835
-+
-+ If in doubt, say N.
-+
- config ARM_TEGRA_CPUFREQ
- bool "TEGRA CPUFreq support"
- depends on ARCH_TEGRA
-diff -Nur linux-3.11.10.orig/drivers/cpufreq/Makefile linux-3.11.10/drivers/cpufreq/Makefile
---- linux-3.11.10.orig/drivers/cpufreq/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/cpufreq/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -76,6 +76,7 @@
- obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
- obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
- obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
-+obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
- obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
-
- ##################################################################################
-diff -Nur linux-3.11.10.orig/drivers/hwmon/bcm2835-hwmon.c linux-3.11.10/drivers/hwmon/bcm2835-hwmon.c
---- linux-3.11.10.orig/drivers/hwmon/bcm2835-hwmon.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/hwmon/bcm2835-hwmon.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,219 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/hwmon.h>
-+#include <linux/hwmon-sysfs.h>
-+#include <linux/platform_device.h>
-+#include <linux/sysfs.h>
-+#include <mach/vcio.h>
-+#include <linux/slab.h>
-+#include <linux/err.h>
-+
-+#define MODULE_NAME "bcm2835_hwmon"
-+
-+/*#define HWMON_DEBUG_ENABLE*/
-+
-+#ifdef HWMON_DEBUG_ENABLE
-+#define print_debug(fmt,...) printk(KERN_INFO "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
-+#else
-+#define print_debug(fmt,...)
-+#endif
-+#define print_err(fmt,...) printk(KERN_ERR "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
-+#define print_info(fmt,...) printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ##__VA_ARGS__)
-+
-+#define VC_TAG_GET_TEMP 0x00030006
-+#define VC_TAG_GET_MAX_TEMP 0x0003000A
-+
-+/* --- STRUCTS --- */
-+struct bcm2835_hwmon_data {
-+ struct device *hwmon_dev;
-+};
-+
-+/* tag part of the message */
-+struct vc_msg_tag {
-+ uint32_t tag_id; /* the tag ID for the temperature */
-+ uint32_t buffer_size; /* size of the buffer (should be 8) */
-+ uint32_t request_code; /* identifies message as a request (should be 0) */
-+ uint32_t id; /* extra ID field (should be 0) */
-+ uint32_t val; /* returned value of the temperature */
-+};
-+
-+/* message structure to be sent to videocore */
-+struct vc_msg {
-+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
-+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
-+ struct vc_msg_tag tag; /* the tag structure above to make */
-+ uint32_t end_tag; /* an end identifier, should be set to NULL */
-+};
-+
-+typedef enum {
-+ TEMP,
-+ MAX_TEMP,
-+} temp_type;
-+
-+/* --- PROTOTYPES --- */
-+static ssize_t bcm2835_get_temp(struct device *dev, struct device_attribute *attr, char *buf);
-+static ssize_t bcm2835_get_name(struct device *dev, struct device_attribute *attr, char *buf);
-+
-+/* --- GLOBALS --- */
-+
-+static struct bcm2835_hwmon_data *bcm2835_data;
-+static struct platform_driver bcm2835_hwmon_driver;
-+
-+static SENSOR_DEVICE_ATTR(name, S_IRUGO,bcm2835_get_name,NULL,0);
-+static SENSOR_DEVICE_ATTR(temp1_input,S_IRUGO,bcm2835_get_temp,NULL,TEMP);
-+static SENSOR_DEVICE_ATTR(temp1_max,S_IRUGO,bcm2835_get_temp,NULL,MAX_TEMP);
-+
-+static struct attribute* bcm2835_attributes[] = {
-+ &sensor_dev_attr_name.dev_attr.attr,
-+ &sensor_dev_attr_temp1_input.dev_attr.attr,
-+ &sensor_dev_attr_temp1_max.dev_attr.attr,
-+ NULL,
-+};
-+
-+static struct attribute_group bcm2835_attr_group = {
-+ .attrs = bcm2835_attributes,
-+};
-+
-+/* --- FUNCTIONS --- */
-+
-+static ssize_t bcm2835_get_name(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ return sprintf(buf,"bcm2835_hwmon\n");
-+}
-+
-+static ssize_t bcm2835_get_temp(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct vc_msg msg;
-+ int result;
-+ uint temp = 0;
-+ int index = ((struct sensor_device_attribute*)to_sensor_dev_attr(attr))->index;
-+
-+ print_debug("IN");
-+
-+ /* wipe all previous message data */
-+ memset(&msg, 0, sizeof msg);
-+
-+ /* determine the message type */
-+ if(index == TEMP)
-+ msg.tag.tag_id = VC_TAG_GET_TEMP;
-+ else if (index == MAX_TEMP)
-+ msg.tag.tag_id = VC_TAG_GET_MAX_TEMP;
-+ else
-+ {
-+ print_debug("Unknown temperature message!");
-+ return -EINVAL;
-+ }
-+
-+ msg.msg_size = sizeof msg;
-+ msg.tag.buffer_size = 8;
-+
-+ /* send the message */
-+ result = bcm_mailbox_property(&msg, sizeof msg);
-+
-+ /* check if it was all ok and return the rate in milli degrees C */
-+ if (result == 0 && (msg.request_code & 0x80000000))
-+ temp = (uint)msg.tag.val;
-+ #ifdef HWMON_DEBUG_ENABLE
-+ else
-+ print_debug("Failed to get temperature!");
-+ #endif
-+ print_debug("Got temperature as %u",temp);
-+ print_debug("OUT");
-+ return sprintf(buf, "%u\n", temp);
-+}
-+
-+
-+static int bcm2835_hwmon_probe(struct platform_device *pdev)
-+{
-+ int err;
-+
-+ print_debug("IN");
-+ print_debug("HWMON Driver has been probed!");
-+
-+ /* check that the device isn't null!*/
-+ if(pdev == NULL)
-+ {
-+ print_debug("Platform device is empty!");
-+ return -ENODEV;
-+ }
-+
-+ /* allocate memory for neccessary data */
-+ bcm2835_data = kzalloc(sizeof(struct bcm2835_hwmon_data),GFP_KERNEL);
-+ if(!bcm2835_data)
-+ {
-+ print_debug("Unable to allocate memory for hwmon data!");
-+ err = -ENOMEM;
-+ goto kzalloc_error;
-+ }
-+
-+ /* create the sysfs files */
-+ if(sysfs_create_group(&pdev->dev.kobj, &bcm2835_attr_group))
-+ {
-+ print_debug("Unable to create sysfs files!");
-+ err = -EFAULT;
-+ goto sysfs_error;
-+ }
-+
-+ /* register the hwmon device */
-+ bcm2835_data->hwmon_dev = hwmon_device_register(&pdev->dev);
-+ if (IS_ERR(bcm2835_data->hwmon_dev))
-+ {
-+ err = PTR_ERR(bcm2835_data->hwmon_dev);
-+ goto hwmon_error;
-+ }
-+ print_debug("OUT");
-+ return 0;
-+
-+ /* error goto's */
-+ hwmon_error:
-+ sysfs_remove_group(&pdev->dev.kobj, &bcm2835_attr_group);
-+
-+ sysfs_error:
-+ kfree(bcm2835_data);
-+
-+ kzalloc_error:
-+
-+ return err;
-+
-+}
-+
-+static int bcm2835_hwmon_remove(struct platform_device *pdev)
-+{
-+ print_debug("IN");
-+ hwmon_device_unregister(bcm2835_data->hwmon_dev);
-+
-+ sysfs_remove_group(&pdev->dev.kobj, &bcm2835_attr_group);
-+ print_debug("OUT");
-+ return 0;
-+}
-+
-+/* Hwmon Driver */
-+static struct platform_driver bcm2835_hwmon_driver = {
-+ .probe = bcm2835_hwmon_probe,
-+ .remove = bcm2835_hwmon_remove,
-+ .driver = {
-+ .name = "bcm2835_hwmon",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Dorian Peake");
-+MODULE_DESCRIPTION("HW Monitor driver for bcm2835 chip");
-+
-+module_platform_driver(bcm2835_hwmon_driver);
-diff -Nur linux-3.11.10.orig/drivers/hwmon/Kconfig linux-3.11.10/drivers/hwmon/Kconfig
---- linux-3.11.10.orig/drivers/hwmon/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/hwmon/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -1543,6 +1543,16 @@
- help
- Support for the A/D converter on MC13783 and MC13892 PMIC.
-
-+config SENSORS_BCM2835
-+ depends on THERMAL_BCM2835=n
-+ tristate "Broadcom BCM2835 HWMON Driver"
-+ help
-+ If you say yes here you get support for the hardware
-+ monitoring features of the BCM2835 Chip
-+
-+ This driver can also be built as a module. If so, the module
-+ will be called bcm2835-hwmon.
-+
- if ACPI
-
- comment "ACPI drivers"
-diff -Nur linux-3.11.10.orig/drivers/hwmon/Makefile linux-3.11.10/drivers/hwmon/Makefile
---- linux-3.11.10.orig/drivers/hwmon/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/hwmon/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -141,6 +141,7 @@
- obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
- obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
- obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
-+obj-$(CONFIG_SENSORS_BCM2835) += bcm2835-hwmon.o
-
- obj-$(CONFIG_PMBUS) += pmbus/
-
-diff -Nur linux-3.11.10.orig/drivers/i2c/busses/i2c-bcm2708.c linux-3.11.10/drivers/i2c/busses/i2c-bcm2708.c
---- linux-3.11.10.orig/drivers/i2c/busses/i2c-bcm2708.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/i2c/busses/i2c-bcm2708.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,408 @@
-+/*
-+ * Driver for Broadcom BCM2708 BSC Controllers
-+ *
-+ * Copyright (C) 2012 Chris Boot & Frank Buss
-+ *
-+ * This driver is inspired by:
-+ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/spinlock.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/platform_device.h>
-+#include <linux/io.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/wait.h>
-+
-+/* BSC register offsets */
-+#define BSC_C 0x00
-+#define BSC_S 0x04
-+#define BSC_DLEN 0x08
-+#define BSC_A 0x0c
-+#define BSC_FIFO 0x10
-+#define BSC_DIV 0x14
-+#define BSC_DEL 0x18
-+#define BSC_CLKT 0x1c
-+
-+/* Bitfields in BSC_C */
-+#define BSC_C_I2CEN 0x00008000
-+#define BSC_C_INTR 0x00000400
-+#define BSC_C_INTT 0x00000200
-+#define BSC_C_INTD 0x00000100
-+#define BSC_C_ST 0x00000080
-+#define BSC_C_CLEAR_1 0x00000020
-+#define BSC_C_CLEAR_2 0x00000010
-+#define BSC_C_READ 0x00000001
-+
-+/* Bitfields in BSC_S */
-+#define BSC_S_CLKT 0x00000200
-+#define BSC_S_ERR 0x00000100
-+#define BSC_S_RXF 0x00000080
-+#define BSC_S_TXE 0x00000040
-+#define BSC_S_RXD 0x00000020
-+#define BSC_S_TXD 0x00000010
-+#define BSC_S_RXR 0x00000008
-+#define BSC_S_TXW 0x00000004
-+#define BSC_S_DONE 0x00000002
-+#define BSC_S_TA 0x00000001
-+
-+#define I2C_TIMEOUT_MS 150
-+
-+#define DRV_NAME "bcm2708_i2c"
-+
-+static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
-+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-+MODULE_PARM_DESC(baudrate, "The I2C baudrate");
-+
-+
-+struct bcm2708_i2c {
-+ struct i2c_adapter adapter;
-+
-+ spinlock_t lock;
-+ void __iomem *base;
-+ int irq;
-+ struct clk *clk;
-+
-+ struct completion done;
-+
-+ struct i2c_msg *msg;
-+ int pos;
-+ int nmsgs;
-+ bool error;
-+};
-+
-+/*
-+ * This function sets the ALT mode on the I2C pins so that we can use them with
-+ * the BSC hardware.
-+ *
-+ * FIXME: This is a hack. Use pinmux / pinctrl.
-+ */
-+static void bcm2708_i2c_init_pinmode(int id)
-+{
-+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
-+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
-+
-+ int pin;
-+ u32 *gpio = ioremap(0x20200000, SZ_16K);
-+
-+ BUG_ON(id != 0 && id != 1);
-+ /* BSC0 is on GPIO 0 & 1, BSC1 is on GPIO 2 & 3 */
-+ for (pin = id*2+0; pin <= id*2+1; pin++) {
-+printk("bcm2708_i2c_init_pinmode(%d,%d)\n", id, pin);
-+ INP_GPIO(pin); /* set mode to GPIO input first */
-+ SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
-+ }
-+
-+ iounmap(gpio);
-+
-+#undef INP_GPIO
-+#undef SET_GPIO_ALT
-+}
-+
-+static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
-+{
-+ return readl(bi->base + reg);
-+}
-+
-+static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
-+{
-+ writel(val, bi->base + reg);
-+}
-+
-+static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
-+{
-+ bcm2708_wr(bi, BSC_C, 0);
-+ bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
-+}
-+
-+static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
-+{
-+ while ((bcm2708_rd(bi, BSC_S) & BSC_S_RXD) && (bi->pos < bi->msg->len))
-+ bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
-+}
-+
-+static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
-+{
-+ while ((bcm2708_rd(bi, BSC_S) & BSC_S_TXD) && (bi->pos < bi->msg->len))
-+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
-+}
-+
-+static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi)
-+{
-+ unsigned long bus_hz;
-+ u32 cdiv;
-+ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
-+
-+ bus_hz = clk_get_rate(bi->clk);
-+ cdiv = bus_hz / baudrate;
-+
-+ if (bi->msg->flags & I2C_M_RD)
-+ c |= BSC_C_INTR | BSC_C_READ;
-+ else
-+ c |= BSC_C_INTT;
-+
-+ bcm2708_wr(bi, BSC_DIV, cdiv);
-+ bcm2708_wr(bi, BSC_A, bi->msg->addr);
-+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
-+ bcm2708_wr(bi, BSC_C, c);
-+}
-+
-+static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
-+{
-+ struct bcm2708_i2c *bi = dev_id;
-+ bool handled = true;
-+ u32 s;
-+
-+ spin_lock(&bi->lock);
-+
-+ /* we may see camera interrupts on the "other" I2C channel
-+ Just return if we've not sent anything */
-+ if (!bi->nmsgs || !bi->msg )
-+ goto early_exit;
-+
-+ s = bcm2708_rd(bi, BSC_S);
-+
-+ if (s & (BSC_S_CLKT | BSC_S_ERR)) {
-+ bcm2708_bsc_reset(bi);
-+ bi->error = true;
-+
-+ /* wake up our bh */
-+ complete(&bi->done);
-+ } else if (s & BSC_S_DONE) {
-+ bi->nmsgs--;
-+
-+ if (bi->msg->flags & I2C_M_RD)
-+ bcm2708_bsc_fifo_drain(bi);
-+
-+ bcm2708_bsc_reset(bi);
-+
-+ if (bi->nmsgs) {
-+ /* advance to next message */
-+ bi->msg++;
-+ bi->pos = 0;
-+ bcm2708_bsc_setup(bi);
-+ } else {
-+ /* wake up our bh */
-+ complete(&bi->done);
-+ }
-+ } else if (s & BSC_S_TXW) {
-+ bcm2708_bsc_fifo_fill(bi);
-+ } else if (s & BSC_S_RXR) {
-+ bcm2708_bsc_fifo_drain(bi);
-+ } else {
-+ handled = false;
-+ }
-+
-+early_exit:
-+ spin_unlock(&bi->lock);
-+
-+ return handled ? IRQ_HANDLED : IRQ_NONE;
-+}
-+
-+static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
-+ struct i2c_msg *msgs, int num)
-+{
-+ struct bcm2708_i2c *bi = adap->algo_data;
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&bi->lock, flags);
-+
-+ INIT_COMPLETION(bi->done);
-+ bi->msg = msgs;
-+ bi->pos = 0;
-+ bi->nmsgs = num;
-+ bi->error = false;
-+
-+ spin_unlock_irqrestore(&bi->lock, flags);
-+
-+ bcm2708_bsc_setup(bi);
-+
-+ ret = wait_for_completion_timeout(&bi->done,
-+ msecs_to_jiffies(I2C_TIMEOUT_MS));
-+ if (ret == 0) {
-+ dev_err(&adap->dev, "transfer timed out\n");
-+ spin_lock_irqsave(&bi->lock, flags);
-+ bcm2708_bsc_reset(bi);
-+ spin_unlock_irqrestore(&bi->lock, flags);
-+ return -ETIMEDOUT;
-+ }
-+
-+ return bi->error ? -EIO : num;
-+}
-+
-+static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
-+{
-+ return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
-+}
-+
-+static struct i2c_algorithm bcm2708_i2c_algorithm = {
-+ .master_xfer = bcm2708_i2c_master_xfer,
-+ .functionality = bcm2708_i2c_functionality,
-+};
-+
-+static int bcm2708_i2c_probe(struct platform_device *pdev)
-+{
-+ struct resource *regs;
-+ int irq, err = -ENOMEM;
-+ struct clk *clk;
-+ struct bcm2708_i2c *bi;
-+ struct i2c_adapter *adap;
-+
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!regs) {
-+ dev_err(&pdev->dev, "could not get IO memory\n");
-+ return -ENXIO;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0) {
-+ dev_err(&pdev->dev, "could not get IRQ\n");
-+ return irq;
-+ }
-+
-+ clk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(clk)) {
-+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
-+ return PTR_ERR(clk);
-+ }
-+
-+ bcm2708_i2c_init_pinmode(pdev->id);
-+
-+ bi = kzalloc(sizeof(*bi), GFP_KERNEL);
-+ if (!bi)
-+ goto out_clk_put;
-+
-+ platform_set_drvdata(pdev, bi);
-+
-+ adap = &bi->adapter;
-+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
-+ adap->algo = &bcm2708_i2c_algorithm;
-+ adap->algo_data = bi;
-+ adap->dev.parent = &pdev->dev;
-+ adap->nr = pdev->id;
-+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
-+
-+ switch (pdev->id) {
-+ case 0:
-+ adap->class = I2C_CLASS_HWMON;
-+ break;
-+ case 1:
-+ adap->class = I2C_CLASS_DDC;
-+ break;
-+ default:
-+ dev_err(&pdev->dev, "can only bind to BSC 0 or 1\n");
-+ err = -ENXIO;
-+ goto out_free_bi;
-+ }
-+
-+ spin_lock_init(&bi->lock);
-+ init_completion(&bi->done);
-+
-+ bi->base = ioremap(regs->start, resource_size(regs));
-+ if (!bi->base) {
-+ dev_err(&pdev->dev, "could not remap memory\n");
-+ goto out_free_bi;
-+ }
-+
-+ bi->irq = irq;
-+ bi->clk = clk;
-+
-+ err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
-+ dev_name(&pdev->dev), bi);
-+ if (err) {
-+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
-+ goto out_iounmap;
-+ }
-+
-+ bcm2708_bsc_reset(bi);
-+
-+ err = i2c_add_numbered_adapter(adap);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
-+ goto out_free_irq;
-+ }
-+
-+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %dk)\n",
-+ pdev->id, (unsigned long)regs->start, irq, baudrate/1000);
-+
-+ return 0;
-+
-+out_free_irq:
-+ free_irq(bi->irq, bi);
-+out_iounmap:
-+ iounmap(bi->base);
-+out_free_bi:
-+ kfree(bi);
-+out_clk_put:
-+ clk_put(clk);
-+ return err;
-+}
-+
-+static int bcm2708_i2c_remove(struct platform_device *pdev)
-+{
-+ struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ i2c_del_adapter(&bi->adapter);
-+ free_irq(bi->irq, bi);
-+ iounmap(bi->base);
-+ clk_disable(bi->clk);
-+ clk_put(bi->clk);
-+ kfree(bi);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm2708_i2c_driver = {
-+ .driver = {
-+ .name = DRV_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = bcm2708_i2c_probe,
-+ .remove = bcm2708_i2c_remove,
-+};
-+
-+// module_platform_driver(bcm2708_i2c_driver);
-+
-+
-+static int __init bcm2708_i2c_init(void)
-+{
-+ return platform_driver_register(&bcm2708_i2c_driver);
-+}
-+
-+static void __exit bcm2708_i2c_exit(void)
-+{
-+ platform_driver_unregister(&bcm2708_i2c_driver);
-+}
-+
-+module_init(bcm2708_i2c_init);
-+module_exit(bcm2708_i2c_exit);
-+
-+
-+
-+MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
-+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:" DRV_NAME);
-diff -Nur linux-3.11.10.orig/drivers/i2c/busses/Kconfig linux-3.11.10/drivers/i2c/busses/Kconfig
---- linux-3.11.10.orig/drivers/i2c/busses/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/i2c/busses/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -345,6 +345,25 @@
- This support is also available as a module. If so, the module
- will be called i2c-bcm2835.
-
-+config I2C_BCM2708
-+ tristate "BCM2708 BSC"
-+ depends on MACH_BCM2708
-+ help
-+ Enabling this option will add BSC (Broadcom Serial Controller)
-+ support for the BCM2708. BSC is a Broadcom proprietary bus compatible
-+ with I2C/TWI/SMBus.
-+
-+config I2C_BCM2708_BAUDRATE
-+ prompt "BCM2708 I2C baudrate"
-+ depends on I2C_BCM2708
-+ int
-+ default 100000
-+ help
-+ Set the I2C baudrate. This will alter the default value. A
-+ different baudrate can be set by using a module parameter as well. If
-+ no parameter is provided when loading, this is the value that will be
-+ used.
-+
- config I2C_BLACKFIN_TWI
- tristate "Blackfin TWI I2C support"
- depends on BLACKFIN
-diff -Nur linux-3.11.10.orig/drivers/i2c/busses/Makefile linux-3.11.10/drivers/i2c/busses/Makefile
---- linux-3.11.10.orig/drivers/i2c/busses/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/i2c/busses/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -32,6 +32,7 @@
- obj-$(CONFIG_I2C_AT91) += i2c-at91.o
- obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
- obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
-+obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
- obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
- obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
- obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
-diff -Nur linux-3.11.10.orig/drivers/media/usb/dvb-usb-v2/rtl28xxu.c linux-3.11.10/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
---- linux-3.11.10.orig/drivers/media/usb/dvb-usb-v2/rtl28xxu.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/media/usb/dvb-usb-v2/rtl28xxu.c 2014-02-07 19:57:28.000000000 +0100
-@@ -1384,6 +1384,10 @@
- &rtl2832u_props, "Compro VideoMate U620F", NULL) },
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
- &rtl2832u_props, "MaxMedia HU394-T", NULL) },
-+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
-+ &rtl2832u_props, "August DVB-T 205", NULL) },
-+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
-+ &rtl2832u_props, "August DVB-T 205", NULL) },
- { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
- &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
- { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
-diff -Nur linux-3.11.10.orig/drivers/misc/Kconfig linux-3.11.10/drivers/misc/Kconfig
---- linux-3.11.10.orig/drivers/misc/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/misc/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -537,4 +537,5 @@
- source "drivers/misc/altera-stapl/Kconfig"
- source "drivers/misc/mei/Kconfig"
- source "drivers/misc/vmw_vmci/Kconfig"
-+source "drivers/misc/vc04_services/Kconfig"
- endmenu
-diff -Nur linux-3.11.10.orig/drivers/misc/Makefile linux-3.11.10/drivers/misc/Makefile
---- linux-3.11.10.orig/drivers/misc/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/misc/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -53,3 +53,4 @@
- obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
- obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
- obj-$(CONFIG_SRAM) += sram.o
-+obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/connections/connection.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/connections/connection.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/connections/connection.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/connections/connection.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,328 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef CONNECTION_H_
-+#define CONNECTION_H_
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/semaphore.h>
-+
-+#include "interface/vchi/vchi_cfg_internal.h"
-+#include "interface/vchi/vchi_common.h"
-+#include "interface/vchi/message_drivers/message.h"
-+
-+/******************************************************************************
-+ Global defs
-+ *****************************************************************************/
-+
-+// Opaque handle for a connection / service pair
-+typedef struct opaque_vchi_connection_connected_service_handle_t *VCHI_CONNECTION_SERVICE_HANDLE_T;
-+
-+// opaque handle to the connection state information
-+typedef struct opaque_vchi_connection_info_t VCHI_CONNECTION_STATE_T;
-+
-+typedef struct vchi_connection_t VCHI_CONNECTION_T;
-+
-+
-+/******************************************************************************
-+ API
-+ *****************************************************************************/
-+
-+// Routine to init a connection with a particular low level driver
-+typedef VCHI_CONNECTION_STATE_T * (*VCHI_CONNECTION_INIT_T)( struct vchi_connection_t * connection,
-+ const VCHI_MESSAGE_DRIVER_T * driver );
-+
-+// Routine to control CRC enabling at a connection level
-+typedef int32_t (*VCHI_CONNECTION_CRC_CONTROL_T)( VCHI_CONNECTION_STATE_T *state_handle,
-+ VCHI_CRC_CONTROL_T control );
-+
-+// Routine to create a service
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_CONNECT_T)( VCHI_CONNECTION_STATE_T *state_handle,
-+ int32_t service_id,
-+ uint32_t rx_fifo_size,
-+ uint32_t tx_fifo_size,
-+ int server,
-+ VCHI_CALLBACK_T callback,
-+ void *callback_param,
-+ int32_t want_crc,
-+ int32_t want_unaligned_bulk_rx,
-+ int32_t want_unaligned_bulk_tx,
-+ VCHI_CONNECTION_SERVICE_HANDLE_T *service_handle );
-+
-+// Routine to close a service
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_DISCONNECT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle );
-+
-+// Routine to queue a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ const void *data,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// scatter-gather (vector) message queueing
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ VCHI_MSG_VECTOR_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// Routine to dequeue a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *data,
-+ uint32_t max_data_size_to_read,
-+ uint32_t *actual_msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to peek at a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to hold a message
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags,
-+ void **message_handle );
-+
-+// Routine to initialise a received message iterator
-+typedef int32_t (*VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ VCHI_MSG_ITER_T *iter,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to release a held message
-+typedef int32_t (*VCHI_CONNECTION_HELD_MSG_RELEASE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *message_handle );
-+
-+// Routine to get info on a held message
-+typedef int32_t (*VCHI_CONNECTION_HELD_MSG_INFO_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *message_handle,
-+ void **data,
-+ int32_t *msg_size,
-+ uint32_t *tx_timestamp,
-+ uint32_t *rx_timestamp );
-+
-+// Routine to check whether the iterator has a next message
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ const VCHI_MSG_ITER_T *iter );
-+
-+// Routine to advance the iterator
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ VCHI_MSG_ITER_T *iter,
-+ void **data,
-+ uint32_t *msg_size );
-+
-+// Routine to remove the last message returned by the iterator
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_REMOVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ VCHI_MSG_ITER_T *iter );
-+
-+// Routine to hold the last message returned by the iterator
-+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HOLD_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
-+ VCHI_MSG_ITER_T *iter,
-+ void **msg_handle );
-+
-+// Routine to transmit bulk data
-+typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ const void *data_src,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle );
-+
-+// Routine to receive data
-+typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
-+ void *data_dst,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle );
-+
-+// Routine to report if a server is available
-+typedef int32_t (*VCHI_CONNECTION_SERVER_PRESENT)( VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t peer_flags );
-+
-+// Routine to report the number of RX slots available
-+typedef int (*VCHI_CONNECTION_RX_SLOTS_AVAILABLE)( const VCHI_CONNECTION_STATE_T *state );
-+
-+// Routine to report the RX slot size
-+typedef uint32_t (*VCHI_CONNECTION_RX_SLOT_SIZE)( const VCHI_CONNECTION_STATE_T *state );
-+
-+// Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
-+typedef void (*VCHI_CONNECTION_RX_BULK_BUFFER_ADDED)(VCHI_CONNECTION_STATE_T *state,
-+ int32_t service,
-+ uint32_t length,
-+ MESSAGE_TX_CHANNEL_T channel,
-+ uint32_t channel_params,
-+ uint32_t data_length,
-+ uint32_t data_offset);
-+
-+// Callback to inform a service that a Xon or Xoff message has been received
-+typedef void (*VCHI_CONNECTION_FLOW_CONTROL)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t xoff);
-+
-+// Callback to inform a service that a server available reply message has been received
-+typedef void (*VCHI_CONNECTION_SERVER_AVAILABLE_REPLY)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, uint32_t flags);
-+
-+// Callback to indicate that bulk auxiliary messages have arrived
-+typedef void (*VCHI_CONNECTION_BULK_AUX_RECEIVED)(VCHI_CONNECTION_STATE_T *state);
-+
-+// Callback to indicate that bulk auxiliary messages have arrived
-+typedef void (*VCHI_CONNECTION_BULK_AUX_TRANSMITTED)(VCHI_CONNECTION_STATE_T *state, void *handle);
-+
-+// Callback with all the connection info you require
-+typedef void (*VCHI_CONNECTION_INFO)(VCHI_CONNECTION_STATE_T *state, uint32_t protocol_version, uint32_t slot_size, uint32_t num_slots, uint32_t min_bulk_size);
-+
-+// Callback to inform of a disconnect
-+typedef void (*VCHI_CONNECTION_DISCONNECT)(VCHI_CONNECTION_STATE_T *state, uint32_t flags);
-+
-+// Callback to inform of a power control request
-+typedef void (*VCHI_CONNECTION_POWER_CONTROL)(VCHI_CONNECTION_STATE_T *state, MESSAGE_TX_CHANNEL_T channel, int32_t enable);
-+
-+// allocate memory suitably aligned for this connection
-+typedef void * (*VCHI_BUFFER_ALLOCATE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, uint32_t * length);
-+
-+// free memory allocated by buffer_allocate
-+typedef void (*VCHI_BUFFER_FREE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, void * address);
-+
-+
-+/******************************************************************************
-+ System driver struct
-+ *****************************************************************************/
-+
-+struct opaque_vchi_connection_api_t
-+{
-+ // Routine to init the connection
-+ VCHI_CONNECTION_INIT_T init;
-+
-+ // Connection-level CRC control
-+ VCHI_CONNECTION_CRC_CONTROL_T crc_control;
-+
-+ // Routine to connect to or create service
-+ VCHI_CONNECTION_SERVICE_CONNECT_T service_connect;
-+
-+ // Routine to disconnect from a service
-+ VCHI_CONNECTION_SERVICE_DISCONNECT_T service_disconnect;
-+
-+ // Routine to queue a message
-+ VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T service_queue_msg;
-+
-+ // scatter-gather (vector) message queue
-+ VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T service_queue_msgv;
-+
-+ // Routine to dequeue a message
-+ VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T service_dequeue_msg;
-+
-+ // Routine to peek at a message
-+ VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T service_peek_msg;
-+
-+ // Routine to hold a message
-+ VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T service_hold_msg;
-+
-+ // Routine to initialise a received message iterator
-+ VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T service_look_ahead_msg;
-+
-+ // Routine to release a message
-+ VCHI_CONNECTION_HELD_MSG_RELEASE_T held_msg_release;
-+
-+ // Routine to get information on a held message
-+ VCHI_CONNECTION_HELD_MSG_INFO_T held_msg_info;
-+
-+ // Routine to check for next message on iterator
-+ VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T msg_iter_has_next;
-+
-+ // Routine to get next message on iterator
-+ VCHI_CONNECTION_MSG_ITER_NEXT_T msg_iter_next;
-+
-+ // Routine to remove the last message returned by iterator
-+ VCHI_CONNECTION_MSG_ITER_REMOVE_T msg_iter_remove;
-+
-+ // Routine to hold the last message returned by iterator
-+ VCHI_CONNECTION_MSG_ITER_HOLD_T msg_iter_hold;
-+
-+ // Routine to transmit bulk data
-+ VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T bulk_queue_transmit;
-+
-+ // Routine to receive data
-+ VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T bulk_queue_receive;
-+
-+ // Routine to report the available servers
-+ VCHI_CONNECTION_SERVER_PRESENT server_present;
-+
-+ // Routine to report the number of RX slots available
-+ VCHI_CONNECTION_RX_SLOTS_AVAILABLE connection_rx_slots_available;
-+
-+ // Routine to report the RX slot size
-+ VCHI_CONNECTION_RX_SLOT_SIZE connection_rx_slot_size;
-+
-+ // Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
-+ VCHI_CONNECTION_RX_BULK_BUFFER_ADDED rx_bulk_buffer_added;
-+
-+ // Callback to inform a service that a Xon or Xoff message has been received
-+ VCHI_CONNECTION_FLOW_CONTROL flow_control;
-+
-+ // Callback to inform a service that a server available reply message has been received
-+ VCHI_CONNECTION_SERVER_AVAILABLE_REPLY server_available_reply;
-+
-+ // Callback to indicate that bulk auxiliary messages have arrived
-+ VCHI_CONNECTION_BULK_AUX_RECEIVED bulk_aux_received;
-+
-+ // Callback to indicate that a bulk auxiliary message has been transmitted
-+ VCHI_CONNECTION_BULK_AUX_TRANSMITTED bulk_aux_transmitted;
-+
-+ // Callback to provide information about the connection
-+ VCHI_CONNECTION_INFO connection_info;
-+
-+ // Callback to notify that peer has requested disconnect
-+ VCHI_CONNECTION_DISCONNECT disconnect;
-+
-+ // Callback to notify that peer has requested power change
-+ VCHI_CONNECTION_POWER_CONTROL power_control;
-+
-+ // allocate memory suitably aligned for this connection
-+ VCHI_BUFFER_ALLOCATE buffer_allocate;
-+
-+ // free memory allocated by buffer_allocate
-+ VCHI_BUFFER_FREE buffer_free;
-+
-+};
-+
-+struct vchi_connection_t {
-+ const VCHI_CONNECTION_API_T *api;
-+ VCHI_CONNECTION_STATE_T *state;
-+#ifdef VCHI_COARSE_LOCKING
-+ struct semaphore sem;
-+#endif
-+};
-+
-+
-+#endif /* CONNECTION_H_ */
-+
-+/****************************** End of file **********************************/
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/message_drivers/message.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/message_drivers/message.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/message_drivers/message.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/message_drivers/message.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,204 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef _VCHI_MESSAGE_H_
-+#define _VCHI_MESSAGE_H_
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/semaphore.h>
-+
-+#include "interface/vchi/vchi_cfg_internal.h"
-+#include "interface/vchi/vchi_common.h"
-+
-+
-+typedef enum message_event_type {
-+ MESSAGE_EVENT_NONE,
-+ MESSAGE_EVENT_NOP,
-+ MESSAGE_EVENT_MESSAGE,
-+ MESSAGE_EVENT_SLOT_COMPLETE,
-+ MESSAGE_EVENT_RX_BULK_PAUSED,
-+ MESSAGE_EVENT_RX_BULK_COMPLETE,
-+ MESSAGE_EVENT_TX_COMPLETE,
-+ MESSAGE_EVENT_MSG_DISCARDED
-+} MESSAGE_EVENT_TYPE_T;
-+
-+typedef enum vchi_msg_flags
-+{
-+ VCHI_MSG_FLAGS_NONE = 0x0,
-+ VCHI_MSG_FLAGS_TERMINATE_DMA = 0x1
-+} VCHI_MSG_FLAGS_T;
-+
-+typedef enum message_tx_channel
-+{
-+ MESSAGE_TX_CHANNEL_MESSAGE = 0,
-+ MESSAGE_TX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
-+} MESSAGE_TX_CHANNEL_T;
-+
-+// Macros used for cycling through bulk channels
-+#define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-+#define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-+
-+typedef enum message_rx_channel
-+{
-+ MESSAGE_RX_CHANNEL_MESSAGE = 0,
-+ MESSAGE_RX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
-+} MESSAGE_RX_CHANNEL_T;
-+
-+// Message receive slot information
-+typedef struct rx_msg_slot_info {
-+
-+ struct rx_msg_slot_info *next;
-+ //struct slot_info *prev;
-+#if !defined VCHI_COARSE_LOCKING
-+ struct semaphore sem;
-+#endif
-+
-+ uint8_t *addr; // base address of slot
-+ uint32_t len; // length of slot in bytes
-+
-+ uint32_t write_ptr; // hardware causes this to advance
-+ uint32_t read_ptr; // this module does the reading
-+ int active; // is this slot in the hardware dma fifo?
-+ uint32_t msgs_parsed; // count how many messages are in this slot
-+ uint32_t msgs_released; // how many messages have been released
-+ void *state; // connection state information
-+ uint8_t ref_count[VCHI_MAX_SERVICES_PER_CONNECTION]; // reference count for slots held by services
-+} RX_MSG_SLOTINFO_T;
-+
-+// The message driver no longer needs to know about the fields of RX_BULK_SLOTINFO_T - sort this out.
-+// In particular, it mustn't use addr and len - they're the client buffer, but the message
-+// driver will be tasked with sending the aligned core section.
-+typedef struct rx_bulk_slotinfo_t {
-+ struct rx_bulk_slotinfo_t *next;
-+
-+ struct semaphore *blocking;
-+
-+ // needed by DMA
-+ void *addr;
-+ uint32_t len;
-+
-+ // needed for the callback
-+ void *service;
-+ void *handle;
-+ VCHI_FLAGS_T flags;
-+} RX_BULK_SLOTINFO_T;
-+
-+
-+/* ----------------------------------------------------------------------
-+ * each connection driver will have a pool of the following struct.
-+ *
-+ * the pool will be managed by vchi_qman_*
-+ * this means there will be multiple queues (single linked lists)
-+ * a given struct message_info will be on exactly one of these queues
-+ * at any one time
-+ * -------------------------------------------------------------------- */
-+typedef struct rx_message_info {
-+
-+ struct message_info *next;
-+ //struct message_info *prev;
-+
-+ uint8_t *addr;
-+ uint32_t len;
-+ RX_MSG_SLOTINFO_T *slot; // points to whichever slot contains this message
-+ uint32_t tx_timestamp;
-+ uint32_t rx_timestamp;
-+
-+} RX_MESSAGE_INFO_T;
-+
-+typedef struct {
-+ MESSAGE_EVENT_TYPE_T type;
-+
-+ struct {
-+ // for messages
-+ void *addr; // address of message
-+ uint16_t slot_delta; // whether this message indicated slot delta
-+ uint32_t len; // length of message
-+ RX_MSG_SLOTINFO_T *slot; // slot this message is in
-+ int32_t service; // service id this message is destined for
-+ uint32_t tx_timestamp; // timestamp from the header
-+ uint32_t rx_timestamp; // timestamp when we parsed it
-+ } message;
-+
-+ // FIXME: cleanup slot reporting...
-+ RX_MSG_SLOTINFO_T *rx_msg;
-+ RX_BULK_SLOTINFO_T *rx_bulk;
-+ void *tx_handle;
-+ MESSAGE_TX_CHANNEL_T tx_channel;
-+
-+} MESSAGE_EVENT_T;
-+
-+
-+// callbacks
-+typedef void VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T( void *state );
-+
-+typedef struct {
-+ VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T *event_callback;
-+} VCHI_MESSAGE_DRIVER_OPEN_T;
-+
-+
-+// handle to this instance of message driver (as returned by ->open)
-+typedef struct opaque_mhandle_t *VCHI_MDRIVER_HANDLE_T;
-+
-+struct opaque_vchi_message_driver_t {
-+ VCHI_MDRIVER_HANDLE_T *(*open)( VCHI_MESSAGE_DRIVER_OPEN_T *params, void *state );
-+ int32_t (*suspending)( VCHI_MDRIVER_HANDLE_T *handle );
-+ int32_t (*resumed)( VCHI_MDRIVER_HANDLE_T *handle );
-+ int32_t (*power_control)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T, int32_t enable );
-+ int32_t (*add_msg_rx_slot)( VCHI_MDRIVER_HANDLE_T *handle, RX_MSG_SLOTINFO_T *slot ); // rx message
-+ int32_t (*add_bulk_rx)( VCHI_MDRIVER_HANDLE_T *handle, void *data, uint32_t len, RX_BULK_SLOTINFO_T *slot ); // rx data (bulk)
-+ int32_t (*send)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, VCHI_MSG_FLAGS_T flags, void *send_handle ); // tx (message & bulk)
-+ void (*next_event)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_EVENT_T *event ); // get the next event from message_driver
-+ int32_t (*enable)( VCHI_MDRIVER_HANDLE_T *handle );
-+ int32_t (*form_message)( VCHI_MDRIVER_HANDLE_T *handle, int32_t service_id, VCHI_MSG_VECTOR_T *vector, uint32_t count, void
-+ *address, uint32_t length_avail, uint32_t max_total_length, int32_t pad_to_fill, int32_t allow_partial );
-+
-+ int32_t (*update_message)( VCHI_MDRIVER_HANDLE_T *handle, void *dest, int16_t *slot_count );
-+ int32_t (*buffer_aligned)( VCHI_MDRIVER_HANDLE_T *handle, int tx, int uncached, const void *address, const uint32_t length );
-+ void * (*allocate_buffer)( VCHI_MDRIVER_HANDLE_T *handle, uint32_t *length );
-+ void (*free_buffer)( VCHI_MDRIVER_HANDLE_T *handle, void *address );
-+ int (*rx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
-+ int (*tx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
-+
-+ int32_t (*tx_supports_terminate)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
-+ uint32_t (*tx_bulk_chunk_size)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
-+ int (*tx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
-+ int (*rx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_RX_CHANNEL_T channel );
-+ void (*form_bulk_aux)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, uint32_t chunk_size, const void **aux_data, int32_t *aux_len );
-+ void (*debug)( VCHI_MDRIVER_HANDLE_T *handle );
-+};
-+
-+
-+#endif // _VCHI_MESSAGE_H_
-+
-+/****************************** End of file ***********************************/
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_cfg.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_cfg.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_cfg.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_cfg.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,224 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_CFG_H_
-+#define VCHI_CFG_H_
-+
-+/****************************************************************************************
-+ * Defines in this first section are part of the VCHI API and may be examined by VCHI
-+ * services.
-+ ***************************************************************************************/
-+
-+/* Required alignment of base addresses for bulk transfer, if unaligned transfers are not enabled */
-+/* Really determined by the message driver, and should be available from a run-time call. */
-+#ifndef VCHI_BULK_ALIGN
-+# if __VCCOREVER__ >= 0x04000000
-+# define VCHI_BULK_ALIGN 32 // Allows for the need to do cache cleans
-+# else
-+# define VCHI_BULK_ALIGN 16
-+# endif
-+#endif
-+
-+/* Required length multiple for bulk transfers, if unaligned transfers are not enabled */
-+/* May be less than or greater than VCHI_BULK_ALIGN */
-+/* Really determined by the message driver, and should be available from a run-time call. */
-+#ifndef VCHI_BULK_GRANULARITY
-+# if __VCCOREVER__ >= 0x04000000
-+# define VCHI_BULK_GRANULARITY 32 // Allows for the need to do cache cleans
-+# else
-+# define VCHI_BULK_GRANULARITY 16
-+# endif
-+#endif
-+
-+/* The largest possible message to be queued with vchi_msg_queue. */
-+#ifndef VCHI_MAX_MSG_SIZE
-+# if defined VCHI_LOCAL_HOST_PORT
-+# define VCHI_MAX_MSG_SIZE 16384 // makes file transfers fast, but should they be using bulk?
-+# else
-+# define VCHI_MAX_MSG_SIZE 4096 // NOTE: THIS MUST BE LARGER THAN OR EQUAL TO THE SIZE OF THE KHRONOS MERGE BUFFER!!
-+# endif
-+#endif
-+
-+/******************************************************************************************
-+ * Defines below are system configuration options, and should not be used by VCHI services.
-+ *****************************************************************************************/
-+
-+/* How many connections can we support? A localhost implementation uses 2 connections,
-+ * 1 for host-app, 1 for VMCS, and these are hooked together by a loopback MPHI VCFW
-+ * driver. */
-+#ifndef VCHI_MAX_NUM_CONNECTIONS
-+# define VCHI_MAX_NUM_CONNECTIONS 3
-+#endif
-+
-+/* How many services can we open per connection? Extending this doesn't cost processing time, just a small
-+ * amount of static memory. */
-+#ifndef VCHI_MAX_SERVICES_PER_CONNECTION
-+# define VCHI_MAX_SERVICES_PER_CONNECTION 36
-+#endif
-+
-+/* Adjust if using a message driver that supports more logical TX channels */
-+#ifndef VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION
-+# define VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION 9 // 1 MPHI + 8 CCP2 logical channels
-+#endif
-+
-+/* Adjust if using a message driver that supports more logical RX channels */
-+#ifndef VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION
-+# define VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION 1 // 1 MPHI
-+#endif
-+
-+/* How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the effective
-+ * receive queue space, less message headers. */
-+#ifndef VCHI_NUM_READ_SLOTS
-+# if defined(VCHI_LOCAL_HOST_PORT)
-+# define VCHI_NUM_READ_SLOTS 4
-+# else
-+# define VCHI_NUM_READ_SLOTS 48
-+# endif
-+#endif
-+
-+/* Do we utilise overrun facility for receive message slots? Can aid peer transmit
-+ * performance. Only define on VideoCore end, talking to host.
-+ */
-+//#define VCHI_MSG_RX_OVERRUN
-+
-+/* How many transmit slots do we use. Generally don't need many, as the hardware driver
-+ * underneath VCHI will usually have its own buffering. */
-+#ifndef VCHI_NUM_WRITE_SLOTS
-+# define VCHI_NUM_WRITE_SLOTS 4
-+#endif
-+
-+/* If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or more slots,
-+ * then it's taking up too much buffer space, and the peer service will be told to stop
-+ * transmitting with an XOFF message. For this to be effective, the VCHI_NUM_READ_SLOTS
-+ * needs to be considerably bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency
-+ * is too high. */
-+#ifndef VCHI_XOFF_THRESHOLD
-+# define VCHI_XOFF_THRESHOLD (VCHI_NUM_READ_SLOTS / 2)
-+#endif
-+
-+/* After we've sent an XOFF, the peer will be told to resume transmission once the local
-+ * service has dequeued/released enough messages that it's now occupying
-+ * VCHI_XON_THRESHOLD slots or fewer. */
-+#ifndef VCHI_XON_THRESHOLD
-+# define VCHI_XON_THRESHOLD (VCHI_NUM_READ_SLOTS / 4)
-+#endif
-+
-+/* A size below which a bulk transfer omits the handshake completely and always goes
-+ * via the message channel, if bulk auxiliary is being sent on that service. (The user
-+ * can guarantee this by enabling unaligned transmits).
-+ * Not API. */
-+#ifndef VCHI_MIN_BULK_SIZE
-+# define VCHI_MIN_BULK_SIZE ( VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096 )
-+#endif
-+
-+/* Maximum size of bulk transmission chunks, for each interface type. A trade-off between
-+ * speed and latency; the smaller the chunk size the better change of messages and other
-+ * bulk transmissions getting in when big bulk transfers are happening. Set to 0 to not
-+ * break transmissions into chunks.
-+ */
-+#ifndef VCHI_MAX_BULK_CHUNK_SIZE_MPHI
-+# define VCHI_MAX_BULK_CHUNK_SIZE_MPHI (16 * 1024)
-+#endif
-+
-+/* NB Chunked CCP2 transmissions violate the letter of the CCP2 spec by using "JPEG8" mode
-+ * with multiple-line frames. Only use if the receiver can cope. */
-+#ifndef VCHI_MAX_BULK_CHUNK_SIZE_CCP2
-+# define VCHI_MAX_BULK_CHUNK_SIZE_CCP2 0
-+#endif
-+
-+/* How many TX messages can we have pending in our transmit slots. Once exhausted,
-+ * vchi_msg_queue will be blocked. */
-+#ifndef VCHI_TX_MSG_QUEUE_SIZE
-+# define VCHI_TX_MSG_QUEUE_SIZE 256
-+#endif
-+
-+/* How many RX messages can we have parsed in the receive slots. Once exhausted, parsing
-+ * will be suspended until older messages are dequeued/released. */
-+#ifndef VCHI_RX_MSG_QUEUE_SIZE
-+# define VCHI_RX_MSG_QUEUE_SIZE 256
-+#endif
-+
-+/* Really should be able to cope if we run out of received message descriptors, by
-+ * suspending parsing as the comment above says, but we don't. This sweeps the issue
-+ * under the carpet. */
-+#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
-+# undef VCHI_RX_MSG_QUEUE_SIZE
-+# define VCHI_RX_MSG_QUEUE_SIZE (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
-+#endif
-+
-+/* How many bulk transmits can we have pending. Once exhausted, vchi_bulk_queue_transmit
-+ * will be blocked. */
-+#ifndef VCHI_TX_BULK_QUEUE_SIZE
-+# define VCHI_TX_BULK_QUEUE_SIZE 64
-+#endif
-+
-+/* How many bulk receives can we have pending. Once exhausted, vchi_bulk_queue_receive
-+ * will be blocked. */
-+#ifndef VCHI_RX_BULK_QUEUE_SIZE
-+# define VCHI_RX_BULK_QUEUE_SIZE 64
-+#endif
-+
-+/* A limit on how many outstanding bulk requests we expect the peer to give us. If
-+ * the peer asks for more than this, VCHI will fail and assert. The number is determined
-+ * by the peer's hardware - it's the number of outstanding requests that can be queued
-+ * on all bulk channels. VC3's MPHI peripheral allows 16. */
-+#ifndef VCHI_MAX_PEER_BULK_REQUESTS
-+# define VCHI_MAX_PEER_BULK_REQUESTS 32
-+#endif
-+
-+/* Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2
-+ * transmitter on and off.
-+ */
-+/*#define VCHI_CCP2TX_MANUAL_POWER*/
-+
-+#ifndef VCHI_CCP2TX_MANUAL_POWER
-+
-+/* Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. Set
-+ * negative for no IDLE.
-+ */
-+# ifndef VCHI_CCP2TX_IDLE_TIMEOUT
-+# define VCHI_CCP2TX_IDLE_TIMEOUT 5
-+# endif
-+
-+/* Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. Set
-+ * negative for no OFF.
-+ */
-+# ifndef VCHI_CCP2TX_OFF_TIMEOUT
-+# define VCHI_CCP2TX_OFF_TIMEOUT 1000
-+# endif
-+
-+#endif /* VCHI_CCP2TX_MANUAL_POWER */
-+
-+#endif /* VCHI_CFG_H_ */
-+
-+/****************************** End of file **********************************/
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_cfg_internal.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,71 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_CFG_INTERNAL_H_
-+#define VCHI_CFG_INTERNAL_H_
-+
-+/****************************************************************************************
-+ * Control optimisation attempts.
-+ ***************************************************************************************/
-+
-+// Don't use lots of short-term locks - use great long ones, reducing the overall locks-per-second
-+#define VCHI_COARSE_LOCKING
-+
-+// Avoid lock then unlock on exit from blocking queue operations (msg tx, bulk rx/tx)
-+// (only relevant if VCHI_COARSE_LOCKING)
-+#define VCHI_ELIDE_BLOCK_EXIT_LOCK
-+
-+// Avoid lock on non-blocking peek
-+// (only relevant if VCHI_COARSE_LOCKING)
-+#define VCHI_AVOID_PEEK_LOCK
-+
-+// Use one slot-handler thread per connection, rather than 1 thread dealing with all connections in rotation.
-+#define VCHI_MULTIPLE_HANDLER_THREADS
-+
-+// Put free descriptors onto the head of the free queue, rather than the tail, so that we don't thrash
-+// our way through the pool of descriptors.
-+#define VCHI_PUSH_FREE_DESCRIPTORS_ONTO_HEAD
-+
-+// Don't issue a MSG_AVAILABLE callback for every single message. Possibly only safe if VCHI_COARSE_LOCKING.
-+#define VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
-+
-+// Don't use message descriptors for TX messages that don't need them
-+#define VCHI_MINIMISE_TX_MSG_DESCRIPTORS
-+
-+// Nano-locks for multiqueue
-+//#define VCHI_MQUEUE_NANOLOCKS
-+
-+// Lock-free(er) dequeuing
-+//#define VCHI_RX_NANOLOCKS
-+
-+#endif /*VCHI_CFG_INTERNAL_H_*/
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_common.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_common.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_common.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_common.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,163 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_COMMON_H_
-+#define VCHI_COMMON_H_
-+
-+
-+//flags used when sending messages (must be bitmapped)
-+typedef enum
-+{
-+ VCHI_FLAGS_NONE = 0x0,
-+ VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE = 0x1, // waits for message to be received, or sent (NB. not the same as being seen on other side)
-+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE = 0x2, // run a callback when message sent
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED = 0x4, // return once the transfer is in a queue ready to go
-+ VCHI_FLAGS_ALLOW_PARTIAL = 0x8,
-+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ = 0x10,
-+ VCHI_FLAGS_CALLBACK_WHEN_DATA_READ = 0x20,
-+
-+ VCHI_FLAGS_ALIGN_SLOT = 0x000080, // internal use only
-+ VCHI_FLAGS_BULK_AUX_QUEUED = 0x010000, // internal use only
-+ VCHI_FLAGS_BULK_AUX_COMPLETE = 0x020000, // internal use only
-+ VCHI_FLAGS_BULK_DATA_QUEUED = 0x040000, // internal use only
-+ VCHI_FLAGS_BULK_DATA_COMPLETE = 0x080000, // internal use only
-+ VCHI_FLAGS_INTERNAL = 0xFF0000
-+} VCHI_FLAGS_T;
-+
-+// constants for vchi_crc_control()
-+typedef enum {
-+ VCHI_CRC_NOTHING = -1,
-+ VCHI_CRC_PER_SERVICE = 0,
-+ VCHI_CRC_EVERYTHING = 1,
-+} VCHI_CRC_CONTROL_T;
-+
-+//callback reasons when an event occurs on a service
-+typedef enum
-+{
-+ VCHI_CALLBACK_REASON_MIN,
-+
-+ //This indicates that there is data available
-+ //handle is the msg id that was transmitted with the data
-+ // When a message is received and there was no FULL message available previously, send callback
-+ // Tasks get kicked by the callback, reset their event and try and read from the fifo until it fails
-+ VCHI_CALLBACK_MSG_AVAILABLE,
-+ VCHI_CALLBACK_MSG_SENT,
-+ VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented
-+
-+ // This indicates that a transfer from the other side has completed
-+ VCHI_CALLBACK_BULK_RECEIVED,
-+ //This indicates that data queued up to be sent has now gone
-+ //handle is the msg id that was used when sending the data
-+ VCHI_CALLBACK_BULK_SENT,
-+ VCHI_CALLBACK_BULK_RX_SPACE_AVAILABLE, // XXX not yet implemented
-+ VCHI_CALLBACK_BULK_TX_SPACE_AVAILABLE, // XXX not yet implemented
-+
-+ VCHI_CALLBACK_SERVICE_CLOSED,
-+
-+ // this side has sent XOFF to peer due to lack of data consumption by service
-+ // (suggests the service may need to take some recovery action if it has
-+ // been deliberately holding off consuming data)
-+ VCHI_CALLBACK_SENT_XOFF,
-+ VCHI_CALLBACK_SENT_XON,
-+
-+ // indicates that a bulk transfer has finished reading the source buffer
-+ VCHI_CALLBACK_BULK_DATA_READ,
-+
-+ // power notification events (currently host side only)
-+ VCHI_CALLBACK_PEER_OFF,
-+ VCHI_CALLBACK_PEER_SUSPENDED,
-+ VCHI_CALLBACK_PEER_ON,
-+ VCHI_CALLBACK_PEER_RESUMED,
-+ VCHI_CALLBACK_FORCED_POWER_OFF,
-+
-+#ifdef USE_VCHIQ_ARM
-+ // some extra notifications provided by vchiq_arm
-+ VCHI_CALLBACK_SERVICE_OPENED,
-+ VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
-+ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
-+#endif
-+
-+ VCHI_CALLBACK_REASON_MAX
-+} VCHI_CALLBACK_REASON_T;
-+
-+//Calback used by all services / bulk transfers
-+typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param
-+ VCHI_CALLBACK_REASON_T reason,
-+ void *handle ); //for transmitting msg's only
-+
-+
-+
-+/*
-+ * Define vector struct for scatter-gather (vector) operations
-+ * Vectors can be nested - if a vector element has negative length, then
-+ * the data pointer is treated as pointing to another vector array, with
-+ * '-vec_len' elements. Thus to append a header onto an existing vector,
-+ * you can do this:
-+ *
-+ * void foo(const VCHI_MSG_VECTOR_T *v, int n)
-+ * {
-+ * VCHI_MSG_VECTOR_T nv[2];
-+ * nv[0].vec_base = my_header;
-+ * nv[0].vec_len = sizeof my_header;
-+ * nv[1].vec_base = v;
-+ * nv[1].vec_len = -n;
-+ * ...
-+ *
-+ */
-+typedef struct vchi_msg_vector {
-+ const void *vec_base;
-+ int32_t vec_len;
-+} VCHI_MSG_VECTOR_T;
-+
-+// Opaque type for a connection API
-+typedef struct opaque_vchi_connection_api_t VCHI_CONNECTION_API_T;
-+
-+// Opaque type for a message driver
-+typedef struct opaque_vchi_message_driver_t VCHI_MESSAGE_DRIVER_T;
-+
-+
-+// Iterator structure for reading ahead through received message queue. Allocated by client,
-+// initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only.
-+// Iterates over messages in queue at the instant of the call to vchi_msg_lookahead -
-+// will not proceed to messages received since. Behaviour is undefined if an iterator
-+// is used again after messages for that service are removed/dequeued by any
-+// means other than vchi_msg_iter_... calls on the iterator itself.
-+typedef struct {
-+ struct opaque_vchi_service_t *service;
-+ void *last;
-+ void *next;
-+ void *remove;
-+} VCHI_MSG_ITER_T;
-+
-+
-+#endif // VCHI_COMMON_H_
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,373 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_H_
-+#define VCHI_H_
-+
-+#include "interface/vchi/vchi_cfg.h"
-+#include "interface/vchi/vchi_common.h"
-+#include "interface/vchi/connections/connection.h"
-+#include "vchi_mh.h"
-+
-+
-+/******************************************************************************
-+ Global defs
-+ *****************************************************************************/
-+
-+#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x))+VCHI_BULK_ALIGN-1) & ~(VCHI_BULK_ALIGN-1))
-+#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN-1))
-+#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN-1))))
-+
-+#ifdef USE_VCHIQ_ARM
-+#define VCHI_BULK_ALIGNED(x) 1
-+#else
-+#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN-1)) == 0)
-+#endif
-+
-+struct vchi_version {
-+ uint32_t version;
-+ uint32_t version_min;
-+};
-+#define VCHI_VERSION(v_) { v_, v_ }
-+#define VCHI_VERSION_EX(v_, m_) { v_, m_ }
-+
-+typedef enum
-+{
-+ VCHI_VEC_POINTER,
-+ VCHI_VEC_HANDLE,
-+ VCHI_VEC_LIST
-+} VCHI_MSG_VECTOR_TYPE_T;
-+
-+typedef struct vchi_msg_vector_ex {
-+
-+ VCHI_MSG_VECTOR_TYPE_T type;
-+ union
-+ {
-+ // a memory handle
-+ struct
-+ {
-+ VCHI_MEM_HANDLE_T handle;
-+ uint32_t offset;
-+ int32_t vec_len;
-+ } handle;
-+
-+ // an ordinary data pointer
-+ struct
-+ {
-+ const void *vec_base;
-+ int32_t vec_len;
-+ } ptr;
-+
-+ // a nested vector list
-+ struct
-+ {
-+ struct vchi_msg_vector_ex *vec;
-+ uint32_t vec_len;
-+ } list;
-+ } u;
-+} VCHI_MSG_VECTOR_EX_T;
-+
-+
-+// Construct an entry in a msg vector for a pointer (p) of length (l)
-+#define VCHI_VEC_POINTER(p,l) VCHI_VEC_POINTER, { { (VCHI_MEM_HANDLE_T)(p), (l) } }
-+
-+// Construct an entry in a msg vector for a message handle (h), starting at offset (o) of length (l)
-+#define VCHI_VEC_HANDLE(h,o,l) VCHI_VEC_HANDLE, { { (h), (o), (l) } }
-+
-+// Macros to manipulate 'FOURCC' values
-+#define MAKE_FOURCC(x) ((int32_t)( (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] ))
-+#define FOURCC_TO_CHAR(x) (x >> 24) & 0xFF,(x >> 16) & 0xFF,(x >> 8) & 0xFF, x & 0xFF
-+
-+
-+// Opaque service information
-+struct opaque_vchi_service_t;
-+
-+// Descriptor for a held message. Allocated by client, initialised by vchi_msg_hold,
-+// vchi_msg_iter_hold or vchi_msg_iter_hold_next. Fields are for internal VCHI use only.
-+typedef struct
-+{
-+ struct opaque_vchi_service_t *service;
-+ void *message;
-+} VCHI_HELD_MSG_T;
-+
-+
-+
-+// structure used to provide the information needed to open a server or a client
-+typedef struct {
-+ struct vchi_version version;
-+ int32_t service_id;
-+ VCHI_CONNECTION_T *connection;
-+ uint32_t rx_fifo_size;
-+ uint32_t tx_fifo_size;
-+ VCHI_CALLBACK_T callback;
-+ void *callback_param;
-+ /* client intends to receive bulk transfers of
-+ odd lengths or into unaligned buffers */
-+ int32_t want_unaligned_bulk_rx;
-+ /* client intends to transmit bulk transfers of
-+ odd lengths or out of unaligned buffers */
-+ int32_t want_unaligned_bulk_tx;
-+ /* client wants to check CRCs on (bulk) xfers.
-+ Only needs to be set at 1 end - will do both directions. */
-+ int32_t want_crc;
-+} SERVICE_CREATION_T;
-+
-+// Opaque handle for a VCHI instance
-+typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T;
-+
-+// Opaque handle for a server or client
-+typedef struct opaque_vchi_service_handle_t *VCHI_SERVICE_HANDLE_T;
-+
-+// Service registration & startup
-+typedef void (*VCHI_SERVICE_INIT)(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
-+
-+typedef struct service_info_tag {
-+ const char * const vll_filename; /* VLL to load to start this service. This is an empty string if VLL is "static" */
-+ VCHI_SERVICE_INIT init; /* Service initialisation function */
-+ void *vll_handle; /* VLL handle; NULL when unloaded or a "static VLL" in build */
-+} SERVICE_INFO_T;
-+
-+/******************************************************************************
-+ Global funcs - implementation is specific to which side you are on (local / remote)
-+ *****************************************************************************/
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+extern /*@observer@*/ VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
-+ const VCHI_MESSAGE_DRIVER_T * low_level);
-+
-+
-+// Routine used to initialise the vchi on both local + remote connections
-+extern int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle );
-+
-+extern int32_t vchi_exit( void );
-+
-+extern int32_t vchi_connect( VCHI_CONNECTION_T **connections,
-+ const uint32_t num_connections,
-+ VCHI_INSTANCE_T instance_handle );
-+
-+//When this is called, ensure that all services have no data pending.
-+//Bulk transfers can remain 'queued'
-+extern int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle );
-+
-+// Global control over bulk CRC checking
-+extern int32_t vchi_crc_control( VCHI_CONNECTION_T *connection,
-+ VCHI_CRC_CONTROL_T control );
-+
-+// helper functions
-+extern void * vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length);
-+extern void vchi_free_buffer(VCHI_SERVICE_HANDLE_T handle, void *address);
-+extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle);
-+
-+
-+/******************************************************************************
-+ Global service API
-+ *****************************************************************************/
-+// Routine to create a named service
-+extern int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle );
-+
-+// Routine to destory a service
-+extern int32_t vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to open a named service
-+extern int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle);
-+
-+extern int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle,
-+ short *peer_version );
-+
-+// Routine to close a named service
-+extern int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to increment ref count on a named service
-+extern int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to decrement ref count on a named service
-+extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to send a message accross a service
-+extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
-+ const void *data,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// scatter-gather (vector) and send message
-+int32_t vchi_msg_queuev_ex( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_VECTOR_EX_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// legacy scatter-gather (vector) and send message, only handles pointers
-+int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_VECTOR_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle );
-+
-+// Routine to receive a msg from a service
-+// Dequeue is equivalent to hold, copy into client buffer, release
-+extern int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
-+ void *data,
-+ uint32_t max_data_size_to_read,
-+ uint32_t *actual_msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to look at a message in place.
-+// The message is not dequeued, so a subsequent call to peek or dequeue
-+// will return the same message.
-+extern int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags );
-+
-+// Routine to remove a message after it has been read in place with peek
-+// The first message on the queue is dequeued.
-+extern int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle );
-+
-+// Routine to look at a message in place.
-+// The message is dequeued, so the caller is left holding it; the descriptor is
-+// filled in and must be released when the user has finished with the message.
-+extern int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
-+ void **data, // } may be NULL, as info can be
-+ uint32_t *msg_size, // } obtained from HELD_MSG_T
-+ VCHI_FLAGS_T flags,
-+ VCHI_HELD_MSG_T *message_descriptor );
-+
-+// Initialise an iterator to look through messages in place
-+extern int32_t vchi_msg_look_ahead( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_ITER_T *iter,
-+ VCHI_FLAGS_T flags );
-+
-+/******************************************************************************
-+ Global service support API - operations on held messages and message iterators
-+ *****************************************************************************/
-+
-+// Routine to get the address of a held message
-+extern void *vchi_held_msg_ptr( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to get the size of a held message
-+extern int32_t vchi_held_msg_size( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to get the transmit timestamp as written into the header by the peer
-+extern uint32_t vchi_held_msg_tx_timestamp( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to get the reception timestamp, written as we parsed the header
-+extern uint32_t vchi_held_msg_rx_timestamp( const VCHI_HELD_MSG_T *message );
-+
-+// Routine to release a held message after it has been processed
-+extern int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message );
-+
-+// Indicates whether the iterator has a next message.
-+extern int32_t vchi_msg_iter_has_next( const VCHI_MSG_ITER_T *iter );
-+
-+// Return the pointer and length for the next message and advance the iterator.
-+extern int32_t vchi_msg_iter_next( VCHI_MSG_ITER_T *iter,
-+ void **data,
-+ uint32_t *msg_size );
-+
-+// Remove the last message returned by vchi_msg_iter_next.
-+// Can only be called once after each call to vchi_msg_iter_next.
-+extern int32_t vchi_msg_iter_remove( VCHI_MSG_ITER_T *iter );
-+
-+// Hold the last message returned by vchi_msg_iter_next.
-+// Can only be called once after each call to vchi_msg_iter_next.
-+extern int32_t vchi_msg_iter_hold( VCHI_MSG_ITER_T *iter,
-+ VCHI_HELD_MSG_T *message );
-+
-+// Return information for the next message, and hold it, advancing the iterator.
-+extern int32_t vchi_msg_iter_hold_next( VCHI_MSG_ITER_T *iter,
-+ void **data, // } may be NULL
-+ uint32_t *msg_size, // }
-+ VCHI_HELD_MSG_T *message );
-+
-+
-+/******************************************************************************
-+ Global bulk API
-+ *****************************************************************************/
-+
-+// Routine to prepare interface for a transfer from the other side
-+extern int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
-+ void *data_dst,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *transfer_handle );
-+
-+
-+// Prepare interface for a transfer from the other side into relocatable memory.
-+int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T h_dst,
-+ uint32_t offset,
-+ uint32_t data_size,
-+ const VCHI_FLAGS_T flags,
-+ void * const bulk_handle );
-+
-+// Routine to queue up data ready for transfer to the other (once they have signalled they are ready)
-+extern int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
-+ const void *data_src,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *transfer_handle );
-+
-+
-+/******************************************************************************
-+ Configuration plumbing
-+ *****************************************************************************/
-+
-+// function prototypes for the different mid layers (the state info gives the different physical connections)
-+extern const VCHI_CONNECTION_API_T *single_get_func_table( void );
-+//extern const VCHI_CONNECTION_API_T *local_server_get_func_table( void );
-+//extern const VCHI_CONNECTION_API_T *local_client_get_func_table( void );
-+
-+// declare all message drivers here
-+const VCHI_MESSAGE_DRIVER_T *vchi_mphi_message_driver_func_table( void );
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+extern int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T h_src,
-+ uint32_t offset,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *transfer_handle );
-+#endif /* VCHI_H_ */
-+
-+/****************************** End of file **********************************/
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_mh.h linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_mh.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchi/vchi_mh.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchi/vchi_mh.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,42 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHI_MH_H_
-+#define VCHI_MH_H_
-+
-+#include <linux/types.h>
-+
-+typedef int32_t VCHI_MEM_HANDLE_T;
-+#define VCHI_MEM_HANDLE_INVALID 0
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,538 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/pagemap.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/version.h>
-+#include <linux/io.h>
-+#include <linux/uaccess.h>
-+#include <asm/pgtable.h>
-+
-+#include <mach/irqs.h>
-+
-+#include <mach/platform.h>
-+#include <mach/vcio.h>
-+
-+#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
-+
-+#define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
-+#define VCHIQ_ARM_ADDRESS(x) ((void *)__virt_to_bus((unsigned)x))
-+
-+#include "vchiq_arm.h"
-+#include "vchiq_2835.h"
-+#include "vchiq_connected.h"
-+
-+#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
-+
-+typedef struct vchiq_2835_state_struct {
-+ int inited;
-+ VCHIQ_ARM_STATE_T arm_state;
-+} VCHIQ_2835_ARM_STATE_T;
-+
-+static char *g_slot_mem;
-+static int g_slot_mem_size;
-+dma_addr_t g_slot_phys;
-+static FRAGMENTS_T *g_fragments_base;
-+static FRAGMENTS_T *g_free_fragments;
-+struct semaphore g_free_fragments_sema;
-+
-+extern int vchiq_arm_log_level;
-+
-+static DEFINE_SEMAPHORE(g_free_fragments_mutex);
-+
-+static irqreturn_t
-+vchiq_doorbell_irq(int irq, void *dev_id);
-+
-+static int
-+create_pagelist(char __user *buf, size_t count, unsigned short type,
-+ struct task_struct *task, PAGELIST_T ** ppagelist);
-+
-+static void
-+free_pagelist(PAGELIST_T *pagelist, int actual);
-+
-+int __init
-+vchiq_platform_init(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
-+ int frag_mem_size;
-+ int err;
-+ int i;
-+
-+ /* Allocate space for the channels in coherent memory */
-+ g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
-+ frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS);
-+
-+ g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size,
-+ &g_slot_phys, GFP_ATOMIC);
-+
-+ if (!g_slot_mem) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to allocate channel memory");
-+ err = -ENOMEM;
-+ goto failed_alloc;
-+ }
-+
-+ WARN_ON(((int)g_slot_mem & (PAGE_SIZE - 1)) != 0);
-+
-+ vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
-+ if (!vchiq_slot_zero) {
-+ err = -EINVAL;
-+ goto failed_init_slots;
-+ }
-+
-+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
-+ (int)g_slot_phys + g_slot_mem_size;
-+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
-+ MAX_FRAGMENTS;
-+
-+ g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size);
-+ g_slot_mem_size += frag_mem_size;
-+
-+ g_free_fragments = g_fragments_base;
-+ for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
-+ *(FRAGMENTS_T **)&g_fragments_base[i] =
-+ &g_fragments_base[i + 1];
-+ }
-+ *(FRAGMENTS_T **)&g_fragments_base[i] = NULL;
-+ sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
-+
-+ if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
-+ VCHIQ_SUCCESS) {
-+ err = -EINVAL;
-+ goto failed_vchiq_init;
-+ }
-+
-+ err = request_irq(VCHIQ_DOORBELL_IRQ, vchiq_doorbell_irq,
-+ IRQF_IRQPOLL, "VCHIQ doorbell",
-+ state);
-+ if (err < 0) {
-+ vchiq_log_error(vchiq_arm_log_level, "%s: failed to register "
-+ "irq=%d err=%d", __func__,
-+ VCHIQ_DOORBELL_IRQ, err);
-+ goto failed_request_irq;
-+ }
-+
-+ /* Send the base address of the slots to VideoCore */
-+
-+ dsb(); /* Ensure all writes have completed */
-+
-+ bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys);
-+
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "vchiq_init - done (slots %x, phys %x)",
-+ (unsigned int)vchiq_slot_zero, g_slot_phys);
-+
-+ vchiq_call_connected_callbacks();
-+
-+ return 0;
-+
-+failed_request_irq:
-+failed_vchiq_init:
-+failed_init_slots:
-+ dma_free_coherent(NULL, g_slot_mem_size, g_slot_mem, g_slot_phys);
-+
-+failed_alloc:
-+ return err;
-+}
-+
-+void __exit
-+vchiq_platform_exit(VCHIQ_STATE_T *state)
-+{
-+ free_irq(VCHIQ_DOORBELL_IRQ, state);
-+ dma_free_coherent(NULL, g_slot_mem_size,
-+ g_slot_mem, g_slot_phys);
-+}
-+
-+
-+VCHIQ_STATUS_T
-+vchiq_platform_init_state(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
-+ ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1;
-+ status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state);
-+ if(status != VCHIQ_SUCCESS)
-+ {
-+ ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0;
-+ }
-+ return status;
-+}
-+
-+VCHIQ_ARM_STATE_T*
-+vchiq_platform_get_arm_state(VCHIQ_STATE_T *state)
-+{
-+ if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited)
-+ {
-+ BUG();
-+ }
-+ return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state;
-+}
-+
-+void
-+remote_event_signal(REMOTE_EVENT_T *event)
-+{
-+ wmb();
-+
-+ event->fired = 1;
-+
-+ dsb(); /* data barrier operation */
-+
-+ if (event->armed) {
-+ /* trigger vc interrupt */
-+
-+ writel(0, __io_address(ARM_0_BELL2));
-+ }
-+}
-+
-+int
-+vchiq_copy_from_user(void *dst, const void *src, int size)
-+{
-+ if ((uint32_t)src < TASK_SIZE) {
-+ return copy_from_user(dst, src, size);
-+ } else {
-+ memcpy(dst, src, size);
-+ return 0;
-+ }
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
-+ void *offset, int size, int dir)
-+{
-+ PAGELIST_T *pagelist;
-+ int ret;
-+
-+ WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
-+
-+ ret = create_pagelist((char __user *)offset, size,
-+ (dir == VCHIQ_BULK_RECEIVE)
-+ ? PAGELIST_READ
-+ : PAGELIST_WRITE,
-+ current,
-+ &pagelist);
-+ if (ret != 0)
-+ return VCHIQ_ERROR;
-+
-+ bulk->handle = memhandle;
-+ bulk->data = VCHIQ_ARM_ADDRESS(pagelist);
-+
-+ /* Store the pagelist address in remote_data, which isn't used by the
-+ slave. */
-+ bulk->remote_data = pagelist;
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+void
-+vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
-+{
-+ if (bulk && bulk->remote_data && bulk->actual)
-+ free_pagelist((PAGELIST_T *)bulk->remote_data, bulk->actual);
-+}
-+
-+void
-+vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
-+{
-+ /*
-+ * This should only be called on the master (VideoCore) side, but
-+ * provide an implementation to avoid the need for ifdefery.
-+ */
-+ BUG();
-+}
-+
-+void
-+vchiq_dump_platform_state(void *dump_context)
-+{
-+ char buf[80];
-+ int len;
-+ len = snprintf(buf, sizeof(buf),
-+ " Platform: 2835 (VC master)");
-+ vchiq_dump(dump_context, buf, len + 1);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_platform_suspend(VCHIQ_STATE_T *state)
-+{
-+ return VCHIQ_ERROR;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_platform_resume(VCHIQ_STATE_T *state)
-+{
-+ return VCHIQ_SUCCESS;
-+}
-+
-+void
-+vchiq_platform_paused(VCHIQ_STATE_T *state)
-+{
-+}
-+
-+void
-+vchiq_platform_resumed(VCHIQ_STATE_T *state)
-+{
-+}
-+
-+int
-+vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
-+{
-+ return 1; // autosuspend not supported - videocore always wanted
-+}
-+
-+int
-+vchiq_platform_use_suspend_timer(void)
-+{
-+ return 0;
-+}
-+void
-+vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
-+{
-+ vchiq_log_info((vchiq_arm_log_level>=VCHIQ_LOG_INFO),"Suspend timer not in use");
-+}
-+void
-+vchiq_platform_handle_timeout(VCHIQ_STATE_T *state)
-+{
-+ (void)state;
-+}
-+/*
-+ * Local functions
-+ */
-+
-+static irqreturn_t
-+vchiq_doorbell_irq(int irq, void *dev_id)
-+{
-+ VCHIQ_STATE_T *state = dev_id;
-+ irqreturn_t ret = IRQ_NONE;
-+ unsigned int status;
-+
-+ /* Read (and clear) the doorbell */
-+ status = readl(__io_address(ARM_0_BELL0));
-+
-+ if (status & 0x4) { /* Was the doorbell rung? */
-+ remote_event_pollall(state);
-+ ret = IRQ_HANDLED;
-+ }
-+
-+ return ret;
-+}
-+
-+/* There is a potential problem with partial cache lines (pages?)
-+** at the ends of the block when reading. If the CPU accessed anything in
-+** the same line (page?) then it may have pulled old data into the cache,
-+** obscuring the new data underneath. We can solve this by transferring the
-+** partial cache lines separately, and allowing the ARM to copy into the
-+** cached area.
-+
-+** N.B. This implementation plays slightly fast and loose with the Linux
-+** driver programming rules, e.g. its use of __virt_to_bus instead of
-+** dma_map_single, but it isn't a multi-platform driver and it benefits
-+** from increased speed as a result.
-+*/
-+
-+static int
-+create_pagelist(char __user *buf, size_t count, unsigned short type,
-+ struct task_struct *task, PAGELIST_T ** ppagelist)
-+{
-+ PAGELIST_T *pagelist;
-+ struct page **pages;
-+ struct page *page;
-+ unsigned long *addrs;
-+ unsigned int num_pages, offset, i;
-+ char *addr, *base_addr, *next_addr;
-+ int run, addridx, actual_pages;
-+
-+ offset = (unsigned int)buf & (PAGE_SIZE - 1);
-+ num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
-+
-+ *ppagelist = NULL;
-+
-+ /* Allocate enough storage to hold the page pointers and the page
-+ ** list
-+ */
-+ pagelist = kmalloc(sizeof(PAGELIST_T) +
-+ (num_pages * sizeof(unsigned long)) +
-+ (num_pages * sizeof(pages[0])),
-+ GFP_KERNEL);
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "create_pagelist - %x", (unsigned int)pagelist);
-+ if (!pagelist)
-+ return -ENOMEM;
-+
-+ addrs = pagelist->addrs;
-+ pages = (struct page **)(addrs + num_pages);
-+
-+ down_read(&task->mm->mmap_sem);
-+ actual_pages = get_user_pages(task, task->mm,
-+ (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages,
-+ (type == PAGELIST_READ) /*Write */ , 0 /*Force */ ,
-+ pages, NULL /*vmas */);
-+ up_read(&task->mm->mmap_sem);
-+
-+ if (actual_pages != num_pages)
-+ {
-+ /* This is probably due to the process being killed */
-+ while (actual_pages > 0)
-+ {
-+ actual_pages--;
-+ page_cache_release(pages[actual_pages]);
-+ }
-+ kfree(pagelist);
-+ if (actual_pages == 0)
-+ actual_pages = -ENOMEM;
-+ return actual_pages;
-+ }
-+
-+ pagelist->length = count;
-+ pagelist->type = type;
-+ pagelist->offset = offset;
-+
-+ /* Group the pages into runs of contiguous pages */
-+
-+ base_addr = VCHIQ_ARM_ADDRESS(page_address(pages[0]));
-+ next_addr = base_addr + PAGE_SIZE;
-+ addridx = 0;
-+ run = 0;
-+
-+ for (i = 1; i < num_pages; i++) {
-+ addr = VCHIQ_ARM_ADDRESS(page_address(pages[i]));
-+ if ((addr == next_addr) && (run < (PAGE_SIZE - 1))) {
-+ next_addr += PAGE_SIZE;
-+ run++;
-+ } else {
-+ addrs[addridx] = (unsigned long)base_addr + run;
-+ addridx++;
-+ base_addr = addr;
-+ next_addr = addr + PAGE_SIZE;
-+ run = 0;
-+ }
-+ }
-+
-+ addrs[addridx] = (unsigned long)base_addr + run;
-+ addridx++;
-+
-+ /* Partial cache lines (fragments) require special measures */
-+ if ((type == PAGELIST_READ) &&
-+ ((pagelist->offset & (CACHE_LINE_SIZE - 1)) ||
-+ ((pagelist->offset + pagelist->length) &
-+ (CACHE_LINE_SIZE - 1)))) {
-+ FRAGMENTS_T *fragments;
-+
-+ if (down_interruptible(&g_free_fragments_sema) != 0) {
-+ kfree(pagelist);
-+ return -EINTR;
-+ }
-+
-+ WARN_ON(g_free_fragments == NULL);
-+
-+ down(&g_free_fragments_mutex);
-+ fragments = (FRAGMENTS_T *) g_free_fragments;
-+ WARN_ON(fragments == NULL);
-+ g_free_fragments = *(FRAGMENTS_T **) g_free_fragments;
-+ up(&g_free_fragments_mutex);
-+ pagelist->type =
-+ PAGELIST_READ_WITH_FRAGMENTS + (fragments -
-+ g_fragments_base);
-+ }
-+
-+ for (page = virt_to_page(pagelist);
-+ page <= virt_to_page(addrs + num_pages - 1); page++) {
-+ flush_dcache_page(page);
-+ }
-+
-+ *ppagelist = pagelist;
-+
-+ return 0;
-+}
-+
-+static void
-+free_pagelist(PAGELIST_T *pagelist, int actual)
-+{
-+ struct page **pages;
-+ unsigned int num_pages, i;
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "free_pagelist - %x, %d", (unsigned int)pagelist, actual);
-+
-+ num_pages =
-+ (pagelist->length + pagelist->offset + PAGE_SIZE - 1) /
-+ PAGE_SIZE;
-+
-+ pages = (struct page **)(pagelist->addrs + num_pages);
-+
-+ /* Deal with any partial cache lines (fragments) */
-+ if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
-+ FRAGMENTS_T *fragments = g_fragments_base +
-+ (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS);
-+ int head_bytes, tail_bytes;
-+ head_bytes = (CACHE_LINE_SIZE - pagelist->offset) &
-+ (CACHE_LINE_SIZE - 1);
-+ tail_bytes = (pagelist->offset + actual) &
-+ (CACHE_LINE_SIZE - 1);
-+
-+ if ((actual >= 0) && (head_bytes != 0)) {
-+ if (head_bytes > actual)
-+ head_bytes = actual;
-+
-+ memcpy((char *)page_address(pages[0]) +
-+ pagelist->offset,
-+ fragments->headbuf,
-+ head_bytes);
-+ }
-+ if ((actual >= 0) && (head_bytes < actual) &&
-+ (tail_bytes != 0)) {
-+ memcpy((char *)page_address(pages[num_pages - 1]) +
-+ ((pagelist->offset + actual) &
-+ (PAGE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1)),
-+ fragments->tailbuf, tail_bytes);
-+ }
-+
-+ down(&g_free_fragments_mutex);
-+ *(FRAGMENTS_T **) fragments = g_free_fragments;
-+ g_free_fragments = fragments;
-+ up(&g_free_fragments_mutex);
-+ up(&g_free_fragments_sema);
-+ }
-+
-+ for (i = 0; i < num_pages; i++) {
-+ if (pagelist->type != PAGELIST_WRITE)
-+ set_page_dirty(pages[i]);
-+ page_cache_release(pages[i]);
-+ }
-+
-+ kfree(pagelist);
-+}
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,42 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_2835_H
-+#define VCHIQ_2835_H
-+
-+#include "vchiq_pagelist.h"
-+
-+#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
-+#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
-+
-+#endif /* VCHIQ_2835_H */
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,2813 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/cdev.h>
-+#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/mm.h>
-+#include <linux/highmem.h>
-+#include <linux/pagemap.h>
-+#include <linux/bug.h>
-+#include <linux/semaphore.h>
-+#include <linux/list.h>
-+#include <linux/proc_fs.h>
-+
-+#include "vchiq_core.h"
-+#include "vchiq_ioctl.h"
-+#include "vchiq_arm.h"
-+
-+#define DEVICE_NAME "vchiq"
-+
-+/* Override the default prefix, which would be vchiq_arm (from the filename) */
-+#undef MODULE_PARAM_PREFIX
-+#define MODULE_PARAM_PREFIX DEVICE_NAME "."
-+
-+#define VCHIQ_MINOR 0
-+
-+/* Some per-instance constants */
-+#define MAX_COMPLETIONS 16
-+#define MAX_SERVICES 64
-+#define MAX_ELEMENTS 8
-+#define MSG_QUEUE_SIZE 64
-+
-+#define KEEPALIVE_VER 1
-+#define KEEPALIVE_VER_MIN KEEPALIVE_VER
-+
-+/* Run time control of log level, based on KERN_XXX level. */
-+int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT;
-+int vchiq_susp_log_level = VCHIQ_LOG_ERROR;
-+
-+#define SUSPEND_TIMER_TIMEOUT_MS 100
-+#define SUSPEND_RETRY_TIMER_TIMEOUT_MS 1000
-+
-+#define VC_SUSPEND_NUM_OFFSET 3 /* number of values before idle which are -ve */
-+static const char *const suspend_state_names[] = {
-+ "VC_SUSPEND_FORCE_CANCELED",
-+ "VC_SUSPEND_REJECTED",
-+ "VC_SUSPEND_FAILED",
-+ "VC_SUSPEND_IDLE",
-+ "VC_SUSPEND_REQUESTED",
-+ "VC_SUSPEND_IN_PROGRESS",
-+ "VC_SUSPEND_SUSPENDED"
-+};
-+#define VC_RESUME_NUM_OFFSET 1 /* number of values before idle which are -ve */
-+static const char *const resume_state_names[] = {
-+ "VC_RESUME_FAILED",
-+ "VC_RESUME_IDLE",
-+ "VC_RESUME_REQUESTED",
-+ "VC_RESUME_IN_PROGRESS",
-+ "VC_RESUME_RESUMED"
-+};
-+/* The number of times we allow force suspend to timeout before actually
-+** _forcing_ suspend. This is to cater for SW which fails to release vchiq
-+** correctly - we don't want to prevent ARM suspend indefinitely in this case.
-+*/
-+#define FORCE_SUSPEND_FAIL_MAX 8
-+
-+/* The time in ms allowed for videocore to go idle when force suspend has been
-+ * requested */
-+#define FORCE_SUSPEND_TIMEOUT_MS 200
-+
-+
-+static void suspend_timer_callback(unsigned long context);
-+static int vchiq_proc_add_instance(VCHIQ_INSTANCE_T instance);
-+static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance);
-+
-+
-+typedef struct user_service_struct {
-+ VCHIQ_SERVICE_T *service;
-+ void *userdata;
-+ VCHIQ_INSTANCE_T instance;
-+ int is_vchi;
-+ int dequeue_pending;
-+ int message_available_pos;
-+ int msg_insert;
-+ int msg_remove;
-+ struct semaphore insert_event;
-+ struct semaphore remove_event;
-+ VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE];
-+} USER_SERVICE_T;
-+
-+struct bulk_waiter_node {
-+ struct bulk_waiter bulk_waiter;
-+ int pid;
-+ struct list_head list;
-+};
-+
-+struct vchiq_instance_struct {
-+ VCHIQ_STATE_T *state;
-+ VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS];
-+ int completion_insert;
-+ int completion_remove;
-+ struct semaphore insert_event;
-+ struct semaphore remove_event;
-+ struct mutex completion_mutex;
-+
-+ int connected;
-+ int closing;
-+ int pid;
-+ int mark;
-+
-+ struct list_head bulk_waiter_list;
-+ struct mutex bulk_waiter_list_mutex;
-+
-+ struct proc_dir_entry *proc_entry;
-+};
-+
-+typedef struct dump_context_struct {
-+ char __user *buf;
-+ size_t actual;
-+ size_t space;
-+ loff_t offset;
-+} DUMP_CONTEXT_T;
-+
-+static struct cdev vchiq_cdev;
-+static dev_t vchiq_devid;
-+static VCHIQ_STATE_T g_state;
-+static struct class *vchiq_class;
-+static struct device *vchiq_dev;
-+static DEFINE_SPINLOCK(msg_queue_spinlock);
-+
-+static const char *const ioctl_names[] = {
-+ "CONNECT",
-+ "SHUTDOWN",
-+ "CREATE_SERVICE",
-+ "REMOVE_SERVICE",
-+ "QUEUE_MESSAGE",
-+ "QUEUE_BULK_TRANSMIT",
-+ "QUEUE_BULK_RECEIVE",
-+ "AWAIT_COMPLETION",
-+ "DEQUEUE_MESSAGE",
-+ "GET_CLIENT_ID",
-+ "GET_CONFIG",
-+ "CLOSE_SERVICE",
-+ "USE_SERVICE",
-+ "RELEASE_SERVICE",
-+ "SET_SERVICE_OPTION",
-+ "DUMP_PHYS_MEM"
-+};
-+
-+vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) ==
-+ (VCHIQ_IOC_MAX + 1));
-+
-+static void
-+dump_phys_mem(void *virt_addr, uint32_t num_bytes);
-+
-+/****************************************************************************
-+*
-+* add_completion
-+*
-+***************************************************************************/
-+
-+static VCHIQ_STATUS_T
-+add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header, USER_SERVICE_T *user_service,
-+ void *bulk_userdata)
-+{
-+ VCHIQ_COMPLETION_DATA_T *completion;
-+ DEBUG_INITIALISE(g_state.local)
-+
-+ while (instance->completion_insert ==
-+ (instance->completion_remove + MAX_COMPLETIONS)) {
-+ /* Out of space - wait for the client */
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "add_completion - completion queue full");
-+ DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
-+ if (down_interruptible(&instance->remove_event) != 0) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback interrupted");
-+ return VCHIQ_RETRY;
-+ } else if (instance->closing) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback closing");
-+ return VCHIQ_ERROR;
-+ }
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ }
-+
-+ completion =
-+ &instance->completions[instance->completion_insert &
-+ (MAX_COMPLETIONS - 1)];
-+
-+ completion->header = header;
-+ completion->reason = reason;
-+ /* N.B. service_userdata is updated while processing AWAIT_COMPLETION */
-+ completion->service_userdata = user_service->service;
-+ completion->bulk_userdata = bulk_userdata;
-+
-+ if (reason == VCHIQ_SERVICE_CLOSED)
-+ /* Take an extra reference, to be held until
-+ this CLOSED notification is delivered. */
-+ lock_service(user_service->service);
-+
-+ /* A write barrier is needed here to ensure that the entire completion
-+ record is written out before the insert point. */
-+ wmb();
-+
-+ if (reason == VCHIQ_MESSAGE_AVAILABLE)
-+ user_service->message_available_pos =
-+ instance->completion_insert;
-+ instance->completion_insert++;
-+
-+ up(&instance->insert_event);
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+/****************************************************************************
-+*
-+* service_callback
-+*
-+***************************************************************************/
-+
-+static VCHIQ_STATUS_T
-+service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
-+ VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
-+{
-+ /* How do we ensure the callback goes to the right client?
-+ ** The service_user data points to a USER_SERVICE_T record containing
-+ ** the original callback and the user state structure, which contains a
-+ ** circular buffer for completion records.
-+ */
-+ USER_SERVICE_T *user_service;
-+ VCHIQ_SERVICE_T *service;
-+ VCHIQ_INSTANCE_T instance;
-+ DEBUG_INITIALISE(g_state.local)
-+
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+
-+ service = handle_to_service(handle);
-+ BUG_ON(!service);
-+ user_service = (USER_SERVICE_T *)service->base.userdata;
-+ instance = user_service->instance;
-+
-+ if (!instance || instance->closing)
-+ return VCHIQ_SUCCESS;
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "service_callback - service %lx(%d), reason %d, header %lx, "
-+ "instance %lx, bulk_userdata %lx",
-+ (unsigned long)user_service,
-+ service->localport,
-+ reason, (unsigned long)header,
-+ (unsigned long)instance, (unsigned long)bulk_userdata);
-+
-+ if (header && user_service->is_vchi) {
-+ spin_lock(&msg_queue_spinlock);
-+ while (user_service->msg_insert ==
-+ (user_service->msg_remove + MSG_QUEUE_SIZE)) {
-+ spin_unlock(&msg_queue_spinlock);
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "service_callback - msg queue full");
-+ /* If there is no MESSAGE_AVAILABLE in the completion
-+ ** queue, add one
-+ */
-+ if ((user_service->message_available_pos -
-+ instance->completion_remove) < 0) {
-+ VCHIQ_STATUS_T status;
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "Inserting extra MESSAGE_AVAILABLE");
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ status = add_completion(instance, reason,
-+ NULL, user_service, bulk_userdata);
-+ if (status != VCHIQ_SUCCESS) {
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ return status;
-+ }
-+ }
-+
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ if (down_interruptible(&user_service->remove_event)
-+ != 0) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback interrupted");
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ return VCHIQ_RETRY;
-+ } else if (instance->closing) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "service_callback closing");
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ return VCHIQ_ERROR;
-+ }
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ spin_lock(&msg_queue_spinlock);
-+ }
-+
-+ user_service->msg_queue[user_service->msg_insert &
-+ (MSG_QUEUE_SIZE - 1)] = header;
-+ user_service->msg_insert++;
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ up(&user_service->insert_event);
-+
-+ /* If there is a thread waiting in DEQUEUE_MESSAGE, or if
-+ ** there is a MESSAGE_AVAILABLE in the completion queue then
-+ ** bypass the completion queue.
-+ */
-+ if (((user_service->message_available_pos -
-+ instance->completion_remove) >= 0) ||
-+ user_service->dequeue_pending) {
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+ user_service->dequeue_pending = 0;
-+ return VCHIQ_SUCCESS;
-+ }
-+
-+ header = NULL;
-+ }
-+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
-+
-+ return add_completion(instance, reason, header, user_service,
-+ bulk_userdata);
-+}
-+
-+/****************************************************************************
-+*
-+* user_service_free
-+*
-+***************************************************************************/
-+static void
-+user_service_free(void *userdata)
-+{
-+ kfree(userdata);
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_ioctl
-+*
-+***************************************************************************/
-+
-+static long
-+vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ VCHIQ_INSTANCE_T instance = file->private_data;
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ VCHIQ_SERVICE_T *service = NULL;
-+ long ret = 0;
-+ int i, rc;
-+ DEBUG_INITIALISE(g_state.local)
-+
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ "vchiq_ioctl - instance %x, cmd %s, arg %lx",
-+ (unsigned int)instance,
-+ ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) &&
-+ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
-+ ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
-+
-+ switch (cmd) {
-+ case VCHIQ_IOC_SHUTDOWN:
-+ if (!instance->connected)
-+ break;
-+
-+ /* Remove all services */
-+ i = 0;
-+ while ((service = next_service_by_instance(instance->state,
-+ instance, &i)) != NULL) {
-+ status = vchiq_remove_service(service->handle);
-+ unlock_service(service);
-+ if (status != VCHIQ_SUCCESS)
-+ break;
-+ }
-+ service = NULL;
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ /* Wake the completion thread and ask it to exit */
-+ instance->closing = 1;
-+ up(&instance->insert_event);
-+ }
-+
-+ break;
-+
-+ case VCHIQ_IOC_CONNECT:
-+ if (instance->connected) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ rc = mutex_lock_interruptible(&instance->state->mutex);
-+ if (rc != 0) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "vchiq: connect: could not lock mutex for "
-+ "state %d: %d",
-+ instance->state->id, rc);
-+ ret = -EINTR;
-+ break;
-+ }
-+ status = vchiq_connect_internal(instance->state, instance);
-+ mutex_unlock(&instance->state->mutex);
-+
-+ if (status == VCHIQ_SUCCESS)
-+ instance->connected = 1;
-+ else
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "vchiq: could not connect: %d", status);
-+ break;
-+
-+ case VCHIQ_IOC_CREATE_SERVICE: {
-+ VCHIQ_CREATE_SERVICE_T args;
-+ USER_SERVICE_T *user_service = NULL;
-+ void *userdata;
-+ int srvstate;
-+
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ user_service = kmalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
-+ if (!user_service) {
-+ ret = -ENOMEM;
-+ break;
-+ }
-+
-+ if (args.is_open) {
-+ if (!instance->connected) {
-+ ret = -ENOTCONN;
-+ kfree(user_service);
-+ break;
-+ }
-+ srvstate = VCHIQ_SRVSTATE_OPENING;
-+ } else {
-+ srvstate =
-+ instance->connected ?
-+ VCHIQ_SRVSTATE_LISTENING :
-+ VCHIQ_SRVSTATE_HIDDEN;
-+ }
-+
-+ userdata = args.params.userdata;
-+ args.params.callback = service_callback;
-+ args.params.userdata = user_service;
-+ service = vchiq_add_service_internal(
-+ instance->state,
-+ &args.params, srvstate,
-+ instance, user_service_free);
-+
-+ if (service != NULL) {
-+ user_service->service = service;
-+ user_service->userdata = userdata;
-+ user_service->instance = instance;
-+ user_service->is_vchi = args.is_vchi;
-+ user_service->dequeue_pending = 0;
-+ user_service->message_available_pos =
-+ instance->completion_remove - 1;
-+ user_service->msg_insert = 0;
-+ user_service->msg_remove = 0;
-+ sema_init(&user_service->insert_event, 0);
-+ sema_init(&user_service->remove_event, 0);
-+
-+ if (args.is_open) {
-+ status = vchiq_open_service_internal
-+ (service, instance->pid);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_remove_service(service->handle);
-+ service = NULL;
-+ ret = (status == VCHIQ_RETRY) ?
-+ -EINTR : -EIO;
-+ break;
-+ }
-+ }
-+
-+ if (copy_to_user((void __user *)
-+ &(((VCHIQ_CREATE_SERVICE_T __user *)
-+ arg)->handle),
-+ (const void *)&service->handle,
-+ sizeof(service->handle)) != 0) {
-+ ret = -EFAULT;
-+ vchiq_remove_service(service->handle);
-+ }
-+
-+ service = NULL;
-+ } else {
-+ ret = -EEXIST;
-+ kfree(user_service);
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_CLOSE_SERVICE: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_service_for_instance(instance, handle);
-+ if (service != NULL)
-+ status = vchiq_close_service(service->handle);
-+ else
-+ ret = -EINVAL;
-+ } break;
-+
-+ case VCHIQ_IOC_REMOVE_SERVICE: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_service_for_instance(instance, handle);
-+ if (service != NULL)
-+ status = vchiq_remove_service(service->handle);
-+ else
-+ ret = -EINVAL;
-+ } break;
-+
-+ case VCHIQ_IOC_USE_SERVICE:
-+ case VCHIQ_IOC_RELEASE_SERVICE: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ service = find_service_for_instance(instance, handle);
-+ if (service != NULL) {
-+ status = (cmd == VCHIQ_IOC_USE_SERVICE) ?
-+ vchiq_use_service_internal(service) :
-+ vchiq_release_service_internal(service);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s: cmd %s returned error %d for "
-+ "service %c%c%c%c:%03d",
-+ __func__,
-+ (cmd == VCHIQ_IOC_USE_SERVICE) ?
-+ "VCHIQ_IOC_USE_SERVICE" :
-+ "VCHIQ_IOC_RELEASE_SERVICE",
-+ status,
-+ VCHIQ_FOURCC_AS_4CHARS(
-+ service->base.fourcc),
-+ service->client_id);
-+ ret = -EINVAL;
-+ }
-+ } else
-+ ret = -EINVAL;
-+ } break;
-+
-+ case VCHIQ_IOC_QUEUE_MESSAGE: {
-+ VCHIQ_QUEUE_MESSAGE_T args;
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ service = find_service_for_instance(instance, args.handle);
-+
-+ if ((service != NULL) && (args.count <= MAX_ELEMENTS)) {
-+ /* Copy elements into kernel space */
-+ VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
-+ if (copy_from_user(elements, args.elements,
-+ args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
-+ status = vchiq_queue_message
-+ (args.handle,
-+ elements, args.count);
-+ else
-+ ret = -EFAULT;
-+ } else {
-+ ret = -EINVAL;
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
-+ case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
-+ VCHIQ_QUEUE_BULK_TRANSFER_T args;
-+ struct bulk_waiter_node *waiter = NULL;
-+ VCHIQ_BULK_DIR_T dir =
-+ (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
-+ VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
-+
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ service = find_service_for_instance(instance, args.handle);
-+ if (!service) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ if (args.mode == VCHIQ_BULK_MODE_BLOCKING) {
-+ waiter = kzalloc(sizeof(struct bulk_waiter_node),
-+ GFP_KERNEL);
-+ if (!waiter) {
-+ ret = -ENOMEM;
-+ break;
-+ }
-+ args.userdata = &waiter->bulk_waiter;
-+ } else if (args.mode == VCHIQ_BULK_MODE_WAITING) {
-+ struct list_head *pos;
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_for_each(pos, &instance->bulk_waiter_list) {
-+ if (list_entry(pos, struct bulk_waiter_node,
-+ list)->pid == current->pid) {
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ break;
-+ }
-+
-+ }
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+ if (!waiter) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "no bulk_waiter found for pid %d",
-+ current->pid);
-+ ret = -ESRCH;
-+ break;
-+ }
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "found bulk_waiter %x for pid %d",
-+ (unsigned int)waiter, current->pid);
-+ args.userdata = &waiter->bulk_waiter;
-+ }
-+ status = vchiq_bulk_transfer
-+ (args.handle,
-+ VCHI_MEM_HANDLE_INVALID,
-+ args.data, args.size,
-+ args.userdata, args.mode,
-+ dir);
-+ if (!waiter)
-+ break;
-+ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
-+ !waiter->bulk_waiter.bulk) {
-+ if (waiter->bulk_waiter.bulk) {
-+ /* Cancel the signal when the transfer
-+ ** completes. */
-+ spin_lock(&bulk_waiter_spinlock);
-+ waiter->bulk_waiter.bulk->userdata = NULL;
-+ spin_unlock(&bulk_waiter_spinlock);
-+ }
-+ kfree(waiter);
-+ } else {
-+ const VCHIQ_BULK_MODE_T mode_waiting =
-+ VCHIQ_BULK_MODE_WAITING;
-+ waiter->pid = current->pid;
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_add(&waiter->list, &instance->bulk_waiter_list);
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "saved bulk_waiter %x for pid %d",
-+ (unsigned int)waiter, current->pid);
-+
-+ if (copy_to_user((void __user *)
-+ &(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
-+ arg)->mode),
-+ (const void *)&mode_waiting,
-+ sizeof(mode_waiting)) != 0)
-+ ret = -EFAULT;
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_AWAIT_COMPLETION: {
-+ VCHIQ_AWAIT_COMPLETION_T args;
-+
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ if (!instance->connected) {
-+ ret = -ENOTCONN;
-+ break;
-+ }
-+
-+ if (copy_from_user(&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ mutex_lock(&instance->completion_mutex);
-+
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ while ((instance->completion_remove ==
-+ instance->completion_insert)
-+ && !instance->closing) {
-+ int rc;
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ mutex_unlock(&instance->completion_mutex);
-+ rc = down_interruptible(&instance->insert_event);
-+ mutex_lock(&instance->completion_mutex);
-+ if (rc != 0) {
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "AWAIT_COMPLETION interrupted");
-+ ret = -EINTR;
-+ break;
-+ }
-+ }
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+
-+ /* A read memory barrier is needed to stop prefetch of a stale
-+ ** completion record
-+ */
-+ rmb();
-+
-+ if (ret == 0) {
-+ int msgbufcount = args.msgbufcount;
-+ for (ret = 0; ret < args.count; ret++) {
-+ VCHIQ_COMPLETION_DATA_T *completion;
-+ VCHIQ_SERVICE_T *service;
-+ USER_SERVICE_T *user_service;
-+ VCHIQ_HEADER_T *header;
-+ if (instance->completion_remove ==
-+ instance->completion_insert)
-+ break;
-+ completion = &instance->completions[
-+ instance->completion_remove &
-+ (MAX_COMPLETIONS - 1)];
-+
-+ service = completion->service_userdata;
-+ user_service = service->base.userdata;
-+ completion->service_userdata =
-+ user_service->userdata;
-+
-+ header = completion->header;
-+ if (header) {
-+ void __user *msgbuf;
-+ int msglen;
-+
-+ msglen = header->size +
-+ sizeof(VCHIQ_HEADER_T);
-+ /* This must be a VCHIQ-style service */
-+ if (args.msgbufsize < msglen) {
-+ vchiq_log_error(
-+ vchiq_arm_log_level,
-+ "header %x: msgbufsize"
-+ " %x < msglen %x",
-+ (unsigned int)header,
-+ args.msgbufsize,
-+ msglen);
-+ WARN(1, "invalid message "
-+ "size\n");
-+ if (ret == 0)
-+ ret = -EMSGSIZE;
-+ break;
-+ }
-+ if (msgbufcount <= 0)
-+ /* Stall here for lack of a
-+ ** buffer for the message. */
-+ break;
-+ /* Get the pointer from user space */
-+ msgbufcount--;
-+ if (copy_from_user(&msgbuf,
-+ (const void __user *)
-+ &args.msgbufs[msgbufcount],
-+ sizeof(msgbuf)) != 0) {
-+ if (ret == 0)
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ /* Copy the message to user space */
-+ if (copy_to_user(msgbuf, header,
-+ msglen) != 0) {
-+ if (ret == 0)
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ /* Now it has been copied, the message
-+ ** can be released. */
-+ vchiq_release_message(service->handle,
-+ header);
-+
-+ /* The completion must point to the
-+ ** msgbuf. */
-+ completion->header = msgbuf;
-+ }
-+
-+ if (completion->reason ==
-+ VCHIQ_SERVICE_CLOSED)
-+ unlock_service(service);
-+
-+ if (copy_to_user((void __user *)(
-+ (size_t)args.buf +
-+ ret * sizeof(VCHIQ_COMPLETION_DATA_T)),
-+ completion,
-+ sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) {
-+ if (ret == 0)
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ instance->completion_remove++;
-+ }
-+
-+ if (msgbufcount != args.msgbufcount) {
-+ if (copy_to_user((void __user *)
-+ &((VCHIQ_AWAIT_COMPLETION_T *)arg)->
-+ msgbufcount,
-+ &msgbufcount,
-+ sizeof(msgbufcount)) != 0) {
-+ ret = -EFAULT;
-+ }
-+ }
-+ }
-+
-+ if (ret != 0)
-+ up(&instance->remove_event);
-+ mutex_unlock(&instance->completion_mutex);
-+ DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-+ } break;
-+
-+ case VCHIQ_IOC_DEQUEUE_MESSAGE: {
-+ VCHIQ_DEQUEUE_MESSAGE_T args;
-+ USER_SERVICE_T *user_service;
-+ VCHIQ_HEADER_T *header;
-+
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ service = find_service_for_instance(instance, args.handle);
-+ if (!service) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ user_service = (USER_SERVICE_T *)service->base.userdata;
-+ if (user_service->is_vchi == 0) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ spin_lock(&msg_queue_spinlock);
-+ if (user_service->msg_remove == user_service->msg_insert) {
-+ if (!args.blocking) {
-+ spin_unlock(&msg_queue_spinlock);
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ ret = -EWOULDBLOCK;
-+ break;
-+ }
-+ user_service->dequeue_pending = 1;
-+ do {
-+ spin_unlock(&msg_queue_spinlock);
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ if (down_interruptible(
-+ &user_service->insert_event) != 0) {
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "DEQUEUE_MESSAGE interrupted");
-+ ret = -EINTR;
-+ break;
-+ }
-+ spin_lock(&msg_queue_spinlock);
-+ } while (user_service->msg_remove ==
-+ user_service->msg_insert);
-+
-+ if (ret)
-+ break;
-+ }
-+
-+ BUG_ON((int)(user_service->msg_insert -
-+ user_service->msg_remove) < 0);
-+
-+ header = user_service->msg_queue[user_service->msg_remove &
-+ (MSG_QUEUE_SIZE - 1)];
-+ user_service->msg_remove++;
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ up(&user_service->remove_event);
-+ if (header == NULL)
-+ ret = -ENOTCONN;
-+ else if (header->size <= args.bufsize) {
-+ /* Copy to user space if msgbuf is not NULL */
-+ if ((args.buf == NULL) ||
-+ (copy_to_user((void __user *)args.buf,
-+ header->data,
-+ header->size) == 0)) {
-+ ret = header->size;
-+ vchiq_release_message(
-+ service->handle,
-+ header);
-+ } else
-+ ret = -EFAULT;
-+ } else {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "header %x: bufsize %x < size %x",
-+ (unsigned int)header, args.bufsize,
-+ header->size);
-+ WARN(1, "invalid size\n");
-+ ret = -EMSGSIZE;
-+ }
-+ DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
-+ } break;
-+
-+ case VCHIQ_IOC_GET_CLIENT_ID: {
-+ VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
-+
-+ ret = vchiq_get_client_id(handle);
-+ } break;
-+
-+ case VCHIQ_IOC_GET_CONFIG: {
-+ VCHIQ_GET_CONFIG_T args;
-+ VCHIQ_CONFIG_T config;
-+
-+ if (copy_from_user(&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ if (args.config_size > sizeof(config)) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+ status = vchiq_get_config(instance, args.config_size, &config);
-+ if (status == VCHIQ_SUCCESS) {
-+ if (copy_to_user((void __user *)args.pconfig,
-+ &config, args.config_size) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ }
-+ } break;
-+
-+ case VCHIQ_IOC_SET_SERVICE_OPTION: {
-+ VCHIQ_SET_SERVICE_OPTION_T args;
-+
-+ if (copy_from_user(
-+ &args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+
-+ service = find_service_for_instance(instance, args.handle);
-+ if (!service) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ status = vchiq_set_service_option(
-+ args.handle, args.option, args.value);
-+ } break;
-+
-+ case VCHIQ_IOC_DUMP_PHYS_MEM: {
-+ VCHIQ_DUMP_MEM_T args;
-+
-+ if (copy_from_user
-+ (&args, (const void __user *)arg,
-+ sizeof(args)) != 0) {
-+ ret = -EFAULT;
-+ break;
-+ }
-+ dump_phys_mem(args.virt_addr, args.num_bytes);
-+ } break;
-+
-+ default:
-+ ret = -ENOTTY;
-+ break;
-+ }
-+
-+ if (service)
-+ unlock_service(service);
-+
-+ if (ret == 0) {
-+ if (status == VCHIQ_ERROR)
-+ ret = -EIO;
-+ else if (status == VCHIQ_RETRY)
-+ ret = -EINTR;
-+ }
-+
-+ if ((status == VCHIQ_SUCCESS) && (ret < 0) && (ret != -EINTR) &&
-+ (ret != -EWOULDBLOCK))
-+ vchiq_log_info(vchiq_arm_log_level,
-+ " ioctl instance %lx, cmd %s -> status %d, %ld",
-+ (unsigned long)instance,
-+ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
-+ ioctl_names[_IOC_NR(cmd)] :
-+ "<invalid>",
-+ status, ret);
-+ else
-+ vchiq_log_trace(vchiq_arm_log_level,
-+ " ioctl instance %lx, cmd %s -> status %d, %ld",
-+ (unsigned long)instance,
-+ (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
-+ ioctl_names[_IOC_NR(cmd)] :
-+ "<invalid>",
-+ status, ret);
-+
-+ return ret;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_open
-+*
-+***************************************************************************/
-+
-+static int
-+vchiq_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode) & 0x0f;
-+ vchiq_log_info(vchiq_arm_log_level, "vchiq_open");
-+ switch (dev) {
-+ case VCHIQ_MINOR: {
-+ int ret;
-+ VCHIQ_STATE_T *state = vchiq_get_state();
-+ VCHIQ_INSTANCE_T instance;
-+
-+ if (!state) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "vchiq has no connection to VideoCore");
-+ return -ENOTCONN;
-+ }
-+
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+ if (!instance)
-+ return -ENOMEM;
-+
-+ instance->state = state;
-+ instance->pid = current->tgid;
-+
-+ ret = vchiq_proc_add_instance(instance);
-+ if (ret != 0) {
-+ kfree(instance);
-+ return ret;
-+ }
-+
-+ sema_init(&instance->insert_event, 0);
-+ sema_init(&instance->remove_event, 0);
-+ mutex_init(&instance->completion_mutex);
-+ mutex_init(&instance->bulk_waiter_list_mutex);
-+ INIT_LIST_HEAD(&instance->bulk_waiter_list);
-+
-+ file->private_data = instance;
-+ } break;
-+
-+ default:
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unknown minor device: %d", dev);
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_release
-+*
-+***************************************************************************/
-+
-+static int
-+vchiq_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode) & 0x0f;
-+ int ret = 0;
-+ switch (dev) {
-+ case VCHIQ_MINOR: {
-+ VCHIQ_INSTANCE_T instance = file->private_data;
-+ VCHIQ_STATE_T *state = vchiq_get_state();
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "vchiq_release: instance=%lx",
-+ (unsigned long)instance);
-+
-+ if (!state) {
-+ ret = -EPERM;
-+ goto out;
-+ }
-+
-+ /* Ensure videocore is awake to allow termination. */
-+ vchiq_use_internal(instance->state, NULL,
-+ USE_TYPE_VCHIQ);
-+
-+ mutex_lock(&instance->completion_mutex);
-+
-+ /* Wake the completion thread and ask it to exit */
-+ instance->closing = 1;
-+ up(&instance->insert_event);
-+
-+ mutex_unlock(&instance->completion_mutex);
-+
-+ /* Wake the slot handler if the completion queue is full. */
-+ up(&instance->remove_event);
-+
-+ /* Mark all services for termination... */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance,
-+ &i)) != NULL) {
-+ USER_SERVICE_T *user_service = service->base.userdata;
-+
-+ /* Wake the slot handler if the msg queue is full. */
-+ up(&user_service->remove_event);
-+
-+ vchiq_terminate_service_internal(service);
-+ unlock_service(service);
-+ }
-+
-+ /* ...and wait for them to die */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance, &i))
-+ != NULL) {
-+ USER_SERVICE_T *user_service = service->base.userdata;
-+
-+ down(&service->remove_event);
-+
-+ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
-+
-+ spin_lock(&msg_queue_spinlock);
-+
-+ while (user_service->msg_remove !=
-+ user_service->msg_insert) {
-+ VCHIQ_HEADER_T *header = user_service->
-+ msg_queue[user_service->msg_remove &
-+ (MSG_QUEUE_SIZE - 1)];
-+ user_service->msg_remove++;
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ if (header)
-+ vchiq_release_message(
-+ service->handle,
-+ header);
-+ spin_lock(&msg_queue_spinlock);
-+ }
-+
-+ spin_unlock(&msg_queue_spinlock);
-+
-+ unlock_service(service);
-+ }
-+
-+ /* Release any closed services */
-+ while (instance->completion_remove !=
-+ instance->completion_insert) {
-+ VCHIQ_COMPLETION_DATA_T *completion;
-+ VCHIQ_SERVICE_T *service;
-+ completion = &instance->completions[
-+ instance->completion_remove &
-+ (MAX_COMPLETIONS - 1)];
-+ service = completion->service_userdata;
-+ if (completion->reason == VCHIQ_SERVICE_CLOSED)
-+ unlock_service(service);
-+ instance->completion_remove++;
-+ }
-+
-+ /* Release the PEER service count. */
-+ vchiq_release_internal(instance->state, NULL);
-+
-+ {
-+ struct list_head *pos, *next;
-+ list_for_each_safe(pos, next,
-+ &instance->bulk_waiter_list) {
-+ struct bulk_waiter_node *waiter;
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "bulk_waiter - cleaned up %x "
-+ "for pid %d",
-+ (unsigned int)waiter, waiter->pid);
-+ kfree(waiter);
-+ }
-+ }
-+
-+ vchiq_proc_remove_instance(instance);
-+
-+ kfree(instance);
-+ file->private_data = NULL;
-+ } break;
-+
-+ default:
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unknown minor device: %d", dev);
-+ ret = -ENXIO;
-+ }
-+
-+out:
-+ return ret;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_dump
-+*
-+***************************************************************************/
-+
-+void
-+vchiq_dump(void *dump_context, const char *str, int len)
-+{
-+ DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context;
-+
-+ if (context->actual < context->space) {
-+ int copy_bytes;
-+ if (context->offset > 0) {
-+ int skip_bytes = min(len, (int)context->offset);
-+ str += skip_bytes;
-+ len -= skip_bytes;
-+ context->offset -= skip_bytes;
-+ if (context->offset > 0)
-+ return;
-+ }
-+ copy_bytes = min(len, (int)(context->space - context->actual));
-+ if (copy_bytes == 0)
-+ return;
-+ if (copy_to_user(context->buf + context->actual, str,
-+ copy_bytes))
-+ context->actual = -EFAULT;
-+ context->actual += copy_bytes;
-+ len -= copy_bytes;
-+
-+ /* If tne terminating NUL is included in the length, then it
-+ ** marks the end of a line and should be replaced with a
-+ ** carriage return. */
-+ if ((len == 0) && (str[copy_bytes - 1] == '\0')) {
-+ char cr = '\n';
-+ if (copy_to_user(context->buf + context->actual - 1,
-+ &cr, 1))
-+ context->actual = -EFAULT;
-+ }
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_dump_platform_instance_state
-+*
-+***************************************************************************/
-+
-+void
-+vchiq_dump_platform_instances(void *dump_context)
-+{
-+ VCHIQ_STATE_T *state = vchiq_get_state();
-+ char buf[80];
-+ int len;
-+ int i;
-+
-+ /* There is no list of instances, so instead scan all services,
-+ marking those that have been dumped. */
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ VCHIQ_INSTANCE_T instance;
-+
-+ if (service && (service->base.callback == service_callback)) {
-+ instance = service->instance;
-+ if (instance)
-+ instance->mark = 0;
-+ }
-+ }
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ VCHIQ_INSTANCE_T instance;
-+
-+ if (service && (service->base.callback == service_callback)) {
-+ instance = service->instance;
-+ if (instance && !instance->mark) {
-+ len = snprintf(buf, sizeof(buf),
-+ "Instance %x: pid %d,%s completions "
-+ "%d/%d",
-+ (unsigned int)instance, instance->pid,
-+ instance->connected ? " connected, " :
-+ "",
-+ instance->completion_insert -
-+ instance->completion_remove,
-+ MAX_COMPLETIONS);
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ instance->mark = 1;
-+ }
-+ }
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_dump_platform_service_state
-+*
-+***************************************************************************/
-+
-+void
-+vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
-+{
-+ USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata;
-+ char buf[80];
-+ int len;
-+
-+ len = snprintf(buf, sizeof(buf), " instance %x",
-+ (unsigned int)service->instance);
-+
-+ if ((service->base.callback == service_callback) &&
-+ user_service->is_vchi) {
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ ", %d/%d messages",
-+ user_service->msg_insert - user_service->msg_remove,
-+ MSG_QUEUE_SIZE);
-+
-+ if (user_service->dequeue_pending)
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ " (dequeue pending)");
-+ }
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+}
-+
-+/****************************************************************************
-+*
-+* dump_user_mem
-+*
-+***************************************************************************/
-+
-+static void
-+dump_phys_mem(void *virt_addr, uint32_t num_bytes)
-+{
-+ int rc;
-+ uint8_t *end_virt_addr = virt_addr + num_bytes;
-+ int num_pages;
-+ int offset;
-+ int end_offset;
-+ int page_idx;
-+ int prev_idx;
-+ struct page *page;
-+ struct page **pages;
-+ uint8_t *kmapped_virt_ptr;
-+
-+ /* Align virtAddr and endVirtAddr to 16 byte boundaries. */
-+
-+ virt_addr = (void *)((unsigned long)virt_addr & ~0x0fuL);
-+ end_virt_addr = (void *)(((unsigned long)end_virt_addr + 15uL) &
-+ ~0x0fuL);
-+
-+ offset = (int)(long)virt_addr & (PAGE_SIZE - 1);
-+ end_offset = (int)(long)end_virt_addr & (PAGE_SIZE - 1);
-+
-+ num_pages = (offset + num_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
-+
-+ pages = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
-+ if (pages == NULL) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to allocation memory for %d pages\n",
-+ num_pages);
-+ return;
-+ }
-+
-+ down_read(&current->mm->mmap_sem);
-+ rc = get_user_pages(current, /* task */
-+ current->mm, /* mm */
-+ (unsigned long)virt_addr, /* start */
-+ num_pages, /* len */
-+ 0, /* write */
-+ 0, /* force */
-+ pages, /* pages (array of page pointers) */
-+ NULL); /* vmas */
-+ up_read(&current->mm->mmap_sem);
-+
-+ prev_idx = -1;
-+ page = NULL;
-+
-+ while (offset < end_offset) {
-+
-+ int page_offset = offset % PAGE_SIZE;
-+ page_idx = offset / PAGE_SIZE;
-+
-+ if (page_idx != prev_idx) {
-+
-+ if (page != NULL)
-+ kunmap(page);
-+ page = pages[page_idx];
-+ kmapped_virt_ptr = kmap(page);
-+
-+ prev_idx = page_idx;
-+ }
-+
-+ if (vchiq_arm_log_level >= VCHIQ_LOG_TRACE)
-+ vchiq_log_dump_mem("ph",
-+ (uint32_t)(unsigned long)&kmapped_virt_ptr[
-+ page_offset],
-+ &kmapped_virt_ptr[page_offset], 16);
-+
-+ offset += 16;
-+ }
-+ if (page != NULL)
-+ kunmap(page);
-+
-+ for (page_idx = 0; page_idx < num_pages; page_idx++)
-+ page_cache_release(pages[page_idx]);
-+
-+ kfree(pages);
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_read
-+*
-+***************************************************************************/
-+
-+static ssize_t
-+vchiq_read(struct file *file, char __user *buf,
-+ size_t count, loff_t *ppos)
-+{
-+ DUMP_CONTEXT_T context;
-+ context.buf = buf;
-+ context.actual = 0;
-+ context.space = count;
-+ context.offset = *ppos;
-+
-+ vchiq_dump_state(&context, &g_state);
-+
-+ *ppos += context.actual;
-+
-+ return context.actual;
-+}
-+
-+VCHIQ_STATE_T *
-+vchiq_get_state(void)
-+{
-+
-+ if (g_state.remote == NULL)
-+ printk(KERN_ERR "%s: g_state.remote == NULL\n", __func__);
-+ else if (g_state.remote->initialised != 1)
-+ printk(KERN_NOTICE "%s: g_state.remote->initialised != 1 (%d)\n",
-+ __func__, g_state.remote->initialised);
-+
-+ return ((g_state.remote != NULL) &&
-+ (g_state.remote->initialised == 1)) ? &g_state : NULL;
-+}
-+
-+static const struct file_operations
-+vchiq_fops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = vchiq_ioctl,
-+ .open = vchiq_open,
-+ .release = vchiq_release,
-+ .read = vchiq_read
-+};
-+
-+/*
-+ * Autosuspend related functionality
-+ */
-+
-+int
-+vchiq_videocore_wanted(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ if (!arm_state)
-+ /* autosuspend not supported - always return wanted */
-+ return 1;
-+ else if (arm_state->blocked_count)
-+ return 1;
-+ else if (!arm_state->videocore_use_count)
-+ /* usage count zero - check for override unless we're forcing */
-+ if (arm_state->resume_blocked)
-+ return 0;
-+ else
-+ return vchiq_platform_videocore_wanted(state);
-+ else
-+ /* non-zero usage count - videocore still required */
-+ return 1;
-+}
-+
-+static VCHIQ_STATUS_T
-+vchiq_keepalive_vchiq_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header,
-+ VCHIQ_SERVICE_HANDLE_T service_user,
-+ void *bulk_user)
-+{
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s callback reason %d", __func__, reason);
-+ return 0;
-+}
-+
-+static int
-+vchiq_keepalive_thread_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_INSTANCE_T instance;
-+ VCHIQ_SERVICE_HANDLE_T ka_handle;
-+
-+ VCHIQ_SERVICE_PARAMS_T params = {
-+ .fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'),
-+ .callback = vchiq_keepalive_vchiq_callback,
-+ .version = KEEPALIVE_VER,
-+ .version_min = KEEPALIVE_VER_MIN
-+ };
-+
-+ status = vchiq_initialise(&instance);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_initialise failed %d", __func__, status);
-+ goto exit;
-+ }
-+
-+ status = vchiq_connect(instance);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_connect failed %d", __func__, status);
-+ goto shutdown;
-+ }
-+
-+ status = vchiq_add_service(instance, &params, &ka_handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_open_service failed %d", __func__, status);
-+ goto shutdown;
-+ }
-+
-+ while (1) {
-+ long rc = 0, uc = 0;
-+ if (wait_for_completion_interruptible(&arm_state->ka_evt)
-+ != 0) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s interrupted", __func__);
-+ flush_signals(current);
-+ continue;
-+ }
-+
-+ /* read and clear counters. Do release_count then use_count to
-+ * prevent getting more releases than uses */
-+ rc = atomic_xchg(&arm_state->ka_release_count, 0);
-+ uc = atomic_xchg(&arm_state->ka_use_count, 0);
-+
-+ /* Call use/release service the requisite number of times.
-+ * Process use before release so use counts don't go negative */
-+ while (uc--) {
-+ atomic_inc(&arm_state->ka_use_ack_count);
-+ status = vchiq_use_service(ka_handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_use_service error %d",
-+ __func__, status);
-+ }
-+ }
-+ while (rc--) {
-+ status = vchiq_release_service(ka_handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s vchiq_release_service error %d",
-+ __func__, status);
-+ }
-+ }
-+ }
-+
-+shutdown:
-+ vchiq_shutdown(instance);
-+exit:
-+ return 0;
-+}
-+
-+
-+
-+VCHIQ_STATUS_T
-+vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (arm_state) {
-+ rwlock_init(&arm_state->susp_res_lock);
-+
-+ init_completion(&arm_state->ka_evt);
-+ atomic_set(&arm_state->ka_use_count, 0);
-+ atomic_set(&arm_state->ka_use_ack_count, 0);
-+ atomic_set(&arm_state->ka_release_count, 0);
-+
-+ init_completion(&arm_state->vc_suspend_complete);
-+
-+ init_completion(&arm_state->vc_resume_complete);
-+ /* Initialise to 'done' state. We only want to block on resume
-+ * completion while videocore is suspended. */
-+ set_resume_state(arm_state, VC_RESUME_RESUMED);
-+
-+ init_completion(&arm_state->resume_blocker);
-+ /* Initialise to 'done' state. We only want to block on this
-+ * completion while resume is blocked */
-+ complete_all(&arm_state->resume_blocker);
-+
-+ init_completion(&arm_state->blocked_blocker);
-+ /* Initialise to 'done' state. We only want to block on this
-+ * completion while things are waiting on the resume blocker */
-+ complete_all(&arm_state->blocked_blocker);
-+
-+ arm_state->suspend_timer_timeout = SUSPEND_TIMER_TIMEOUT_MS;
-+ arm_state->suspend_timer_running = 0;
-+ init_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer.data = (unsigned long)(state);
-+ arm_state->suspend_timer.function = suspend_timer_callback;
-+
-+ arm_state->first_connect = 0;
-+
-+ }
-+ return status;
-+}
-+
-+/*
-+** Functions to modify the state variables;
-+** set_suspend_state
-+** set_resume_state
-+**
-+** There are more state variables than we might like, so ensure they remain in
-+** step. Suspend and resume state are maintained separately, since most of
-+** these state machines can operate independently. However, there are a few
-+** states where state transitions in one state machine cause a reset to the
-+** other state machine. In addition, there are some completion events which
-+** need to occur on state machine reset and end-state(s), so these are also
-+** dealt with in these functions.
-+**
-+** In all states we set the state variable according to the input, but in some
-+** cases we perform additional steps outlined below;
-+**
-+** VC_SUSPEND_IDLE - Initialise the suspend completion at the same time.
-+** The suspend completion is completed after any suspend
-+** attempt. When we reset the state machine we also reset
-+** the completion. This reset occurs when videocore is
-+** resumed, and also if we initiate suspend after a suspend
-+** failure.
-+**
-+** VC_SUSPEND_IN_PROGRESS - This state is considered the point of no return for
-+** suspend - ie from this point on we must try to suspend
-+** before resuming can occur. We therefore also reset the
-+** resume state machine to VC_RESUME_IDLE in this state.
-+**
-+** VC_SUSPEND_SUSPENDED - Suspend has completed successfully. Also call
-+** complete_all on the suspend completion to notify
-+** anything waiting for suspend to happen.
-+**
-+** VC_SUSPEND_REJECTED - Videocore rejected suspend. Videocore will also
-+** initiate resume, so no need to alter resume state.
-+** We call complete_all on the suspend completion to notify
-+** of suspend rejection.
-+**
-+** VC_SUSPEND_FAILED - We failed to initiate videocore suspend. We notify the
-+** suspend completion and reset the resume state machine.
-+**
-+** VC_RESUME_IDLE - Initialise the resume completion at the same time. The
-+** resume completion is in it's 'done' state whenever
-+** videcore is running. Therfore, the VC_RESUME_IDLE state
-+** implies that videocore is suspended.
-+** Hence, any thread which needs to wait until videocore is
-+** running can wait on this completion - it will only block
-+** if videocore is suspended.
-+**
-+** VC_RESUME_RESUMED - Resume has completed successfully. Videocore is running.
-+** Call complete_all on the resume completion to unblock
-+** any threads waiting for resume. Also reset the suspend
-+** state machine to it's idle state.
-+**
-+** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists.
-+*/
-+
-+inline void
-+set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_suspend_status new_state)
-+{
-+ /* set the state in all cases */
-+ arm_state->vc_suspend_state = new_state;
-+
-+ /* state specific additional actions */
-+ switch (new_state) {
-+ case VC_SUSPEND_FORCE_CANCELED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ break;
-+ case VC_SUSPEND_REJECTED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ break;
-+ case VC_SUSPEND_FAILED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ arm_state->vc_resume_state = VC_RESUME_RESUMED;
-+ complete_all(&arm_state->vc_resume_complete);
-+ break;
-+ case VC_SUSPEND_IDLE:
-+ INIT_COMPLETION(arm_state->vc_suspend_complete);
-+ break;
-+ case VC_SUSPEND_REQUESTED:
-+ break;
-+ case VC_SUSPEND_IN_PROGRESS:
-+ set_resume_state(arm_state, VC_RESUME_IDLE);
-+ break;
-+ case VC_SUSPEND_SUSPENDED:
-+ complete_all(&arm_state->vc_suspend_complete);
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+}
-+
-+inline void
-+set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_resume_status new_state)
-+{
-+ /* set the state in all cases */
-+ arm_state->vc_resume_state = new_state;
-+
-+ /* state specific additional actions */
-+ switch (new_state) {
-+ case VC_RESUME_FAILED:
-+ break;
-+ case VC_RESUME_IDLE:
-+ INIT_COMPLETION(arm_state->vc_resume_complete);
-+ break;
-+ case VC_RESUME_REQUESTED:
-+ break;
-+ case VC_RESUME_IN_PROGRESS:
-+ break;
-+ case VC_RESUME_RESUMED:
-+ complete_all(&arm_state->vc_resume_complete);
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+}
-+
-+
-+/* should be called with the write lock held */
-+inline void
-+start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ del_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer.expires = jiffies +
-+ msecs_to_jiffies(arm_state->
-+ suspend_timer_timeout);
-+ add_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer_running = 1;
-+}
-+
-+/* should be called with the write lock held */
-+static inline void
-+stop_suspend_timer(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ if (arm_state->suspend_timer_running) {
-+ del_timer(&arm_state->suspend_timer);
-+ arm_state->suspend_timer_running = 0;
-+ }
-+}
-+
-+static inline int
-+need_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ return (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) &&
-+ (arm_state->vc_resume_state < VC_RESUME_REQUESTED) &&
-+ vchiq_videocore_wanted(state);
-+}
-+
-+static int
-+block_resume(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ int status = VCHIQ_SUCCESS;
-+ const unsigned long timeout_val =
-+ msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS);
-+ int resume_count = 0;
-+
-+ /* Allow any threads which were blocked by the last force suspend to
-+ * complete if they haven't already. Only give this one shot; if
-+ * blocked_count is incremented after blocked_blocker is completed
-+ * (which only happens when blocked_count hits 0) then those threads
-+ * will have to wait until next time around */
-+ if (arm_state->blocked_count) {
-+ INIT_COMPLETION(arm_state->blocked_blocker);
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
-+ "blocked clients", __func__);
-+ if (wait_for_completion_interruptible_timeout(
-+ &arm_state->blocked_blocker, timeout_val)
-+ <= 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s wait for "
-+ "previously blocked clients failed" , __func__);
-+ status = VCHIQ_ERROR;
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s previously blocked "
-+ "clients resumed", __func__);
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ }
-+
-+ /* We need to wait for resume to complete if it's in process */
-+ while (arm_state->vc_resume_state != VC_RESUME_RESUMED &&
-+ arm_state->vc_resume_state > VC_RESUME_IDLE) {
-+ if (resume_count > 1) {
-+ status = VCHIQ_ERROR;
-+ vchiq_log_error(vchiq_susp_log_level, "%s waited too "
-+ "many times for resume" , __func__);
-+ goto out;
-+ }
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ vchiq_log_info(vchiq_susp_log_level, "%s wait for resume",
-+ __func__);
-+ if (wait_for_completion_interruptible_timeout(
-+ &arm_state->vc_resume_complete, timeout_val)
-+ <= 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s wait for "
-+ "resume failed (%s)", __func__,
-+ resume_state_names[arm_state->vc_resume_state +
-+ VC_RESUME_NUM_OFFSET]);
-+ status = VCHIQ_ERROR;
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__);
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ resume_count++;
-+ }
-+ INIT_COMPLETION(arm_state->resume_blocker);
-+ arm_state->resume_blocked = 1;
-+
-+out:
-+ return status;
-+}
-+
-+static inline void
-+unblock_resume(VCHIQ_ARM_STATE_T *arm_state)
-+{
-+ complete_all(&arm_state->resume_blocker);
-+ arm_state->resume_blocked = 0;
-+}
-+
-+/* Initiate suspend via slot handler. Should be called with the write lock
-+ * held */
-+VCHIQ_STATUS_T
-+vchiq_arm_vcsuspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+ status = VCHIQ_SUCCESS;
-+
-+
-+ switch (arm_state->vc_suspend_state) {
-+ case VC_SUSPEND_REQUESTED:
-+ vchiq_log_info(vchiq_susp_log_level, "%s: suspend already "
-+ "requested", __func__);
-+ break;
-+ case VC_SUSPEND_IN_PROGRESS:
-+ vchiq_log_info(vchiq_susp_log_level, "%s: suspend already in "
-+ "progress", __func__);
-+ break;
-+
-+ default:
-+ /* We don't expect to be in other states, so log but continue
-+ * anyway */
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s unexpected suspend state %s", __func__,
-+ suspend_state_names[arm_state->vc_suspend_state +
-+ VC_SUSPEND_NUM_OFFSET]);
-+ /* fall through */
-+ case VC_SUSPEND_REJECTED:
-+ case VC_SUSPEND_FAILED:
-+ /* Ensure any idle state actions have been run */
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+ /* fall through */
-+ case VC_SUSPEND_IDLE:
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: suspending", __func__);
-+ set_suspend_state(arm_state, VC_SUSPEND_REQUESTED);
-+ /* kick the slot handler thread to initiate suspend */
-+ request_poll(state, NULL, 0);
-+ break;
-+ }
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
-+ return status;
-+}
-+
-+void
-+vchiq_platform_check_suspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int susp = 0;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->vc_suspend_state == VC_SUSPEND_REQUESTED &&
-+ arm_state->vc_resume_state == VC_RESUME_RESUMED) {
-+ set_suspend_state(arm_state, VC_SUSPEND_IN_PROGRESS);
-+ susp = 1;
-+ }
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (susp)
-+ vchiq_platform_suspend(state);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return;
-+}
-+
-+
-+static void
-+output_timeout_error(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ char service_err[50] = "";
-+ int vc_use_count = arm_state->videocore_use_count;
-+ int active_services = state->unused_service;
-+ int i;
-+
-+ if (!arm_state->videocore_use_count) {
-+ snprintf(service_err, 50, " Videocore usecount is 0");
-+ goto output_msg;
-+ }
-+ for (i = 0; i < active_services; i++) {
-+ VCHIQ_SERVICE_T *service_ptr = state->services[i];
-+ if (service_ptr && service_ptr->service_use_count &&
-+ (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE)) {
-+ snprintf(service_err, 50, " %c%c%c%c(%d) service has "
-+ "use count %d%s", VCHIQ_FOURCC_AS_4CHARS(
-+ service_ptr->base.fourcc),
-+ service_ptr->client_id,
-+ service_ptr->service_use_count,
-+ service_ptr->service_use_count ==
-+ vc_use_count ? "" : " (+ more)");
-+ break;
-+ }
-+ }
-+
-+output_msg:
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "timed out waiting for vc suspend (%d).%s",
-+ arm_state->autosuspend_override, service_err);
-+
-+}
-+
-+/* Try to get videocore into suspended state, regardless of autosuspend state.
-+** We don't actually force suspend, since videocore may get into a bad state
-+** if we force suspend at a bad time. Instead, we wait for autosuspend to
-+** determine a good point to suspend. If this doesn't happen within 100ms we
-+** report failure.
-+**
-+** Returns VCHIQ_SUCCESS if videocore suspended successfully, VCHIQ_RETRY if
-+** videocore failed to suspend in time or VCHIQ_ERROR if interrupted.
-+*/
-+VCHIQ_STATUS_T
-+vchiq_arm_force_suspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ long rc = 0;
-+ int repeat = -1;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+
-+ status = block_resume(arm_state);
-+ if (status != VCHIQ_SUCCESS)
-+ goto unlock;
-+ if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
-+ /* Already suspended - just block resume and exit */
-+ vchiq_log_info(vchiq_susp_log_level, "%s already suspended",
-+ __func__);
-+ status = VCHIQ_SUCCESS;
-+ goto unlock;
-+ } else if (arm_state->vc_suspend_state <= VC_SUSPEND_IDLE) {
-+ /* initiate suspend immediately in the case that we're waiting
-+ * for the timeout */
-+ stop_suspend_timer(arm_state);
-+ if (!vchiq_videocore_wanted(state)) {
-+ vchiq_log_info(vchiq_susp_log_level, "%s videocore "
-+ "idle, initiating suspend", __func__);
-+ status = vchiq_arm_vcsuspend(state);
-+ } else if (arm_state->autosuspend_override <
-+ FORCE_SUSPEND_FAIL_MAX) {
-+ vchiq_log_info(vchiq_susp_log_level, "%s letting "
-+ "videocore go idle", __func__);
-+ status = VCHIQ_SUCCESS;
-+ } else {
-+ vchiq_log_warning(vchiq_susp_log_level, "%s failed too "
-+ "many times - attempting suspend", __func__);
-+ status = vchiq_arm_vcsuspend(state);
-+ }
-+ } else {
-+ vchiq_log_info(vchiq_susp_log_level, "%s videocore suspend "
-+ "in progress - wait for completion", __func__);
-+ status = VCHIQ_SUCCESS;
-+ }
-+
-+ /* Wait for suspend to happen due to system idle (not forced..) */
-+ if (status != VCHIQ_SUCCESS)
-+ goto unblock_resume;
-+
-+ do {
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ rc = wait_for_completion_interruptible_timeout(
-+ &arm_state->vc_suspend_complete,
-+ msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS));
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (rc < 0) {
-+ vchiq_log_warning(vchiq_susp_log_level, "%s "
-+ "interrupted waiting for suspend", __func__);
-+ status = VCHIQ_ERROR;
-+ goto unblock_resume;
-+ } else if (rc == 0) {
-+ if (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) {
-+ /* Repeat timeout once if in progress */
-+ if (repeat < 0) {
-+ repeat = 1;
-+ continue;
-+ }
-+ }
-+ arm_state->autosuspend_override++;
-+ output_timeout_error(state);
-+
-+ status = VCHIQ_RETRY;
-+ goto unblock_resume;
-+ }
-+ } while (0 < (repeat--));
-+
-+ /* Check and report state in case we need to abort ARM suspend */
-+ if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED) {
-+ status = VCHIQ_RETRY;
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s videocore suspend failed (state %s)", __func__,
-+ suspend_state_names[arm_state->vc_suspend_state +
-+ VC_SUSPEND_NUM_OFFSET]);
-+ /* Reset the state only if it's still in an error state.
-+ * Something could have already initiated another suspend. */
-+ if (arm_state->vc_suspend_state < VC_SUSPEND_IDLE)
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+
-+ goto unblock_resume;
-+ }
-+
-+ /* successfully suspended - unlock and exit */
-+ goto unlock;
-+
-+unblock_resume:
-+ /* all error states need to unblock resume before exit */
-+ unblock_resume(arm_state);
-+
-+unlock:
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
-+ return status;
-+}
-+
-+void
-+vchiq_check_suspend(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED &&
-+ arm_state->first_connect &&
-+ !vchiq_videocore_wanted(state)) {
-+ vchiq_arm_vcsuspend(state);
-+ }
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return;
-+}
-+
-+
-+int
-+vchiq_arm_allow_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int resume = 0;
-+ int ret = -1;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ unblock_resume(arm_state);
-+ resume = vchiq_check_resume(state);
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (resume) {
-+ if (wait_for_completion_interruptible(
-+ &arm_state->vc_resume_complete) < 0) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s interrupted", __func__);
-+ /* failed, cannot accurately derive suspend
-+ * state, so exit early. */
-+ goto out;
-+ }
-+ }
-+
-+ read_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: Videocore remains suspended", __func__);
-+ } else {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: Videocore resumed", __func__);
-+ ret = 0;
-+ }
-+ read_unlock_bh(&arm_state->susp_res_lock);
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-+ return ret;
-+}
-+
-+/* This function should be called with the write lock held */
-+int
-+vchiq_check_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int resume = 0;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ if (need_resume(state)) {
-+ set_resume_state(arm_state, VC_RESUME_REQUESTED);
-+ request_poll(state, NULL, 0);
-+ resume = 1;
-+ }
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return resume;
-+}
-+
-+void
-+vchiq_platform_check_resume(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int res = 0;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (arm_state->wake_address == 0) {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: already awake", __func__);
-+ goto unlock;
-+ }
-+ if (arm_state->vc_resume_state == VC_RESUME_IN_PROGRESS) {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s: already resuming", __func__);
-+ goto unlock;
-+ }
-+
-+ if (arm_state->vc_resume_state == VC_RESUME_REQUESTED) {
-+ set_resume_state(arm_state, VC_RESUME_IN_PROGRESS);
-+ res = 1;
-+ } else
-+ vchiq_log_trace(vchiq_susp_log_level,
-+ "%s: not resuming (resume state %s)", __func__,
-+ resume_state_names[arm_state->vc_resume_state +
-+ VC_RESUME_NUM_OFFSET]);
-+
-+unlock:
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (res)
-+ vchiq_platform_resume(state);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-+ return;
-+
-+}
-+
-+
-+
-+VCHIQ_STATUS_T
-+vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ enum USE_TYPE_E use_type)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
-+ char entity[16];
-+ int *entity_uc;
-+ int local_uc, local_entity_uc;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ if (use_type == USE_TYPE_VCHIQ) {
-+ sprintf(entity, "VCHIQ: ");
-+ entity_uc = &arm_state->peer_use_count;
-+ } else if (service) {
-+ sprintf(entity, "%c%c%c%c:%03d",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->client_id);
-+ entity_uc = &service->service_use_count;
-+ } else {
-+ vchiq_log_error(vchiq_susp_log_level, "%s null service "
-+ "ptr", __func__);
-+ ret = VCHIQ_ERROR;
-+ goto out;
-+ }
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ while (arm_state->resume_blocked) {
-+ /* If we call 'use' while force suspend is waiting for suspend,
-+ * then we're about to block the thread which the force is
-+ * waiting to complete, so we're bound to just time out. In this
-+ * case, set the suspend state such that the wait will be
-+ * canceled, so we can complete as quickly as possible. */
-+ if (arm_state->resume_blocked && arm_state->vc_suspend_state ==
-+ VC_SUSPEND_IDLE) {
-+ set_suspend_state(arm_state, VC_SUSPEND_FORCE_CANCELED);
-+ break;
-+ }
-+ /* If suspend is already in progress then we need to block */
-+ if (!try_wait_for_completion(&arm_state->resume_blocker)) {
-+ /* Indicate that there are threads waiting on the resume
-+ * blocker. These need to be allowed to complete before
-+ * a _second_ call to force suspend can complete,
-+ * otherwise low priority threads might never actually
-+ * continue */
-+ arm_state->blocked_count++;
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
-+ "blocked - waiting...", __func__, entity);
-+ if (wait_for_completion_killable(
-+ &arm_state->resume_blocker) != 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s %s "
-+ "wait for resume blocker interrupted",
-+ __func__, entity);
-+ ret = VCHIQ_ERROR;
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ arm_state->blocked_count--;
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
-+ "unblocked", __func__, entity);
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (--arm_state->blocked_count == 0)
-+ complete_all(&arm_state->blocked_blocker);
-+ }
-+ }
-+
-+ stop_suspend_timer(arm_state);
-+
-+ local_uc = ++arm_state->videocore_use_count;
-+ local_entity_uc = ++(*entity_uc);
-+
-+ /* If there's a pending request which hasn't yet been serviced then
-+ * just clear it. If we're past VC_SUSPEND_REQUESTED state then
-+ * vc_resume_complete will block until we either resume or fail to
-+ * suspend */
-+ if (arm_state->vc_suspend_state <= VC_SUSPEND_REQUESTED)
-+ set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-+
-+ if ((use_type != USE_TYPE_SERVICE_NO_RESUME) && need_resume(state)) {
-+ set_resume_state(arm_state, VC_RESUME_REQUESTED);
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d",
-+ __func__, entity, local_entity_uc, local_uc);
-+ request_poll(state, NULL, 0);
-+ } else
-+ vchiq_log_trace(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d",
-+ __func__, entity, *entity_uc, local_uc);
-+
-+
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+ /* Completion is in a done state when we're not suspended, so this won't
-+ * block for the non-suspended case. */
-+ if (!try_wait_for_completion(&arm_state->vc_resume_complete)) {
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume",
-+ __func__, entity);
-+ if (wait_for_completion_killable(
-+ &arm_state->vc_resume_complete) != 0) {
-+ vchiq_log_error(vchiq_susp_log_level, "%s %s wait for "
-+ "resume interrupted", __func__, entity);
-+ ret = VCHIQ_ERROR;
-+ goto out;
-+ }
-+ vchiq_log_info(vchiq_susp_log_level, "%s %s resumed", __func__,
-+ entity);
-+ }
-+
-+ if (ret == VCHIQ_SUCCESS) {
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0);
-+ while (ack_cnt && (status == VCHIQ_SUCCESS)) {
-+ /* Send the use notify to videocore */
-+ status = vchiq_send_remote_use_active(state);
-+ if (status == VCHIQ_SUCCESS)
-+ ack_cnt--;
-+ else
-+ atomic_add(ack_cnt,
-+ &arm_state->ka_use_ack_count);
-+ }
-+ }
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-+ return ret;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ VCHIQ_STATUS_T ret = VCHIQ_SUCCESS;
-+ char entity[16];
-+ int *entity_uc;
-+ int local_uc, local_entity_uc;
-+
-+ if (!arm_state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ if (service) {
-+ sprintf(entity, "%c%c%c%c:%03d",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->client_id);
-+ entity_uc = &service->service_use_count;
-+ } else {
-+ sprintf(entity, "PEER: ");
-+ entity_uc = &arm_state->peer_use_count;
-+ }
-+
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (!arm_state->videocore_use_count || !(*entity_uc)) {
-+ /* Don't use BUG_ON - don't allow user thread to crash kernel */
-+ WARN_ON(!arm_state->videocore_use_count);
-+ WARN_ON(!(*entity_uc));
-+ ret = VCHIQ_ERROR;
-+ goto unlock;
-+ }
-+ local_uc = --arm_state->videocore_use_count;
-+ local_entity_uc = --(*entity_uc);
-+
-+ if (!vchiq_videocore_wanted(state)) {
-+ if (vchiq_platform_use_suspend_timer() &&
-+ !arm_state->resume_blocked) {
-+ /* Only use the timer if we're not trying to force
-+ * suspend (=> resume_blocked) */
-+ start_suspend_timer(arm_state);
-+ } else {
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d - suspending",
-+ __func__, entity, *entity_uc,
-+ arm_state->videocore_use_count);
-+ vchiq_arm_vcsuspend(state);
-+ }
-+ } else
-+ vchiq_log_trace(vchiq_susp_log_level,
-+ "%s %s count %d, state count %d",
-+ __func__, entity, *entity_uc,
-+ arm_state->videocore_use_count);
-+
-+unlock:
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+
-+out:
-+ vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
-+ return ret;
-+}
-+
-+void
-+vchiq_on_remote_use(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+ atomic_inc(&arm_state->ka_use_count);
-+ complete(&arm_state->ka_evt);
-+}
-+
-+void
-+vchiq_on_remote_release(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+ atomic_inc(&arm_state->ka_release_count);
-+ complete(&arm_state->ka_evt);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_use_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ return vchiq_use_internal(service->state, service, USE_TYPE_SERVICE);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_release_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ return vchiq_release_internal(service->state, service);
-+}
-+
-+static void suspend_timer_callback(unsigned long context)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *)context;
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ if (!arm_state)
-+ goto out;
-+ vchiq_log_info(vchiq_susp_log_level,
-+ "%s - suspend timer expired - check suspend", __func__);
-+ vchiq_check_suspend(state);
-+out:
-+ return;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_use_service_no_resume(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ if (service) {
-+ ret = vchiq_use_internal(service->state, service,
-+ USE_TYPE_SERVICE_NO_RESUME);
-+ unlock_service(service);
-+ }
-+ return ret;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ if (service) {
-+ ret = vchiq_use_internal(service->state, service,
-+ USE_TYPE_SERVICE);
-+ unlock_service(service);
-+ }
-+ return ret;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ if (service) {
-+ ret = vchiq_release_internal(service->state, service);
-+ unlock_service(service);
-+ }
-+ return ret;
-+}
-+
-+void
-+vchiq_dump_service_use_state(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ int i, j = 0;
-+ /* Only dump 64 services */
-+ static const int local_max_services = 64;
-+ /* If there's more than 64 services, only dump ones with
-+ * non-zero counts */
-+ int only_nonzero = 0;
-+ static const char *nz = "<-- preventing suspend";
-+
-+ enum vc_suspend_status vc_suspend_state;
-+ enum vc_resume_status vc_resume_state;
-+ int peer_count;
-+ int vc_use_count;
-+ int active_services;
-+ struct service_data_struct {
-+ int fourcc;
-+ int clientid;
-+ int use_count;
-+ } service_data[local_max_services];
-+
-+ if (!arm_state)
-+ return;
-+
-+ read_lock_bh(&arm_state->susp_res_lock);
-+ vc_suspend_state = arm_state->vc_suspend_state;
-+ vc_resume_state = arm_state->vc_resume_state;
-+ peer_count = arm_state->peer_use_count;
-+ vc_use_count = arm_state->videocore_use_count;
-+ active_services = state->unused_service;
-+ if (active_services > local_max_services)
-+ only_nonzero = 1;
-+
-+ for (i = 0; (i < active_services) && (j < local_max_services); i++) {
-+ VCHIQ_SERVICE_T *service_ptr = state->services[i];
-+ if (!service_ptr)
-+ continue;
-+
-+ if (only_nonzero && !service_ptr->service_use_count)
-+ continue;
-+
-+ if (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE) {
-+ service_data[j].fourcc = service_ptr->base.fourcc;
-+ service_data[j].clientid = service_ptr->client_id;
-+ service_data[j++].use_count = service_ptr->
-+ service_use_count;
-+ }
-+ }
-+
-+ read_unlock_bh(&arm_state->susp_res_lock);
-+
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "-- Videcore suspend state: %s --",
-+ suspend_state_names[vc_suspend_state + VC_SUSPEND_NUM_OFFSET]);
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "-- Videcore resume state: %s --",
-+ resume_state_names[vc_resume_state + VC_RESUME_NUM_OFFSET]);
-+
-+ if (only_nonzero)
-+ vchiq_log_warning(vchiq_susp_log_level, "Too many active "
-+ "services (%d). Only dumping up to first %d services "
-+ "with non-zero use-count", active_services,
-+ local_max_services);
-+
-+ for (i = 0; i < j; i++) {
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "----- %c%c%c%c:%d service count %d %s",
-+ VCHIQ_FOURCC_AS_4CHARS(service_data[i].fourcc),
-+ service_data[i].clientid,
-+ service_data[i].use_count,
-+ service_data[i].use_count ? nz : "");
-+ }
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "----- VCHIQ use count count %d", peer_count);
-+ vchiq_log_warning(vchiq_susp_log_level,
-+ "--- Overall vchiq instance use count %d", vc_use_count);
-+
-+ vchiq_dump_platform_use_state(state);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_check_service(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state;
-+ VCHIQ_STATUS_T ret = VCHIQ_ERROR;
-+
-+ if (!service || !service->state)
-+ goto out;
-+
-+ vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-+
-+ arm_state = vchiq_platform_get_arm_state(service->state);
-+
-+ read_lock_bh(&arm_state->susp_res_lock);
-+ if (service->service_use_count)
-+ ret = VCHIQ_SUCCESS;
-+ read_unlock_bh(&arm_state->susp_res_lock);
-+
-+ if (ret == VCHIQ_ERROR) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "%s ERROR - %c%c%c%c:%d service count %d, "
-+ "state count %d, videocore suspend state %s", __func__,
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->client_id, service->service_use_count,
-+ arm_state->videocore_use_count,
-+ suspend_state_names[arm_state->vc_suspend_state +
-+ VC_SUSPEND_NUM_OFFSET]);
-+ vchiq_dump_service_use_state(service->state);
-+ }
-+out:
-+ return ret;
-+}
-+
-+/* stub functions */
-+void vchiq_on_remote_use_active(VCHIQ_STATE_T *state)
-+{
-+ (void)state;
-+}
-+
-+void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
-+ VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate)
-+{
-+ VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
-+ vchiq_log_info(vchiq_susp_log_level, "%d: %s->%s", state->id,
-+ get_conn_state_name(oldstate), get_conn_state_name(newstate));
-+ if (state->conn_state == VCHIQ_CONNSTATE_CONNECTED) {
-+ write_lock_bh(&arm_state->susp_res_lock);
-+ if (!arm_state->first_connect) {
-+ char threadname[10];
-+ arm_state->first_connect = 1;
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ snprintf(threadname, sizeof(threadname), "VCHIQka-%d",
-+ state->id);
-+ arm_state->ka_thread = kthread_create(
-+ &vchiq_keepalive_thread_func,
-+ (void *)state,
-+ threadname);
-+ if (arm_state->ka_thread == NULL) {
-+ vchiq_log_error(vchiq_susp_log_level,
-+ "vchiq: FATAL: couldn't create thread %s",
-+ threadname);
-+ } else {
-+ wake_up_process(arm_state->ka_thread);
-+ }
-+ } else
-+ write_unlock_bh(&arm_state->susp_res_lock);
-+ }
-+}
-+
-+
-+/****************************************************************************
-+*
-+* vchiq_init - called when the module is loaded.
-+*
-+***************************************************************************/
-+
-+static int __init
-+vchiq_init(void)
-+{
-+ int err;
-+ void *ptr_err;
-+
-+ /* create proc entries */
-+ err = vchiq_proc_init();
-+ if (err != 0)
-+ goto failed_proc_init;
-+
-+ err = alloc_chrdev_region(&vchiq_devid, VCHIQ_MINOR, 1, DEVICE_NAME);
-+ if (err != 0) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to allocate device number");
-+ goto failed_alloc_chrdev;
-+ }
-+ cdev_init(&vchiq_cdev, &vchiq_fops);
-+ vchiq_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&vchiq_cdev, vchiq_devid, 1);
-+ if (err != 0) {
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "Unable to register device");
-+ goto failed_cdev_add;
-+ }
-+
-+ /* create sysfs entries */
-+ vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
-+ ptr_err = vchiq_class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ vchiq_dev = device_create(vchiq_class, NULL,
-+ vchiq_devid, NULL, "vchiq");
-+ ptr_err = vchiq_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ err = vchiq_platform_init(&g_state);
-+ if (err != 0)
-+ goto failed_platform_init;
-+
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "vchiq: initialised - version %d (min %d), device %d.%d",
-+ VCHIQ_VERSION, VCHIQ_VERSION_MIN,
-+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
-+
-+ return 0;
-+
-+failed_platform_init:
-+ device_destroy(vchiq_class, vchiq_devid);
-+failed_device_create:
-+ class_destroy(vchiq_class);
-+failed_class_create:
-+ cdev_del(&vchiq_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(vchiq_devid, 1);
-+failed_alloc_chrdev:
-+ vchiq_proc_deinit();
-+failed_proc_init:
-+ vchiq_log_warning(vchiq_arm_log_level, "could not load vchiq");
-+ return err;
-+}
-+
-+static int vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int use_count = 0, i;
-+ i = 0;
-+ while ((service = next_service_by_instance(instance->state,
-+ instance, &i)) != NULL) {
-+ use_count += service->service_use_count;
-+ unlock_service(service);
-+ }
-+ return use_count;
-+}
-+
-+/* read the per-process use-count */
-+static int proc_read_use_count(char *page, char **start,
-+ off_t off, int count,
-+ int *eof, void *data)
-+{
-+ VCHIQ_INSTANCE_T instance = data;
-+ int len, use_count;
-+
-+ use_count = vchiq_instance_get_use_count(instance);
-+ len = snprintf(page+off, count, "%d\n", use_count);
-+
-+ return len;
-+}
-+
-+/* add an instance (process) to the proc entries */
-+static int vchiq_proc_add_instance(VCHIQ_INSTANCE_T instance)
-+{
-+#if 1
-+ return 0;
-+#else
-+ char pidstr[32];
-+ struct proc_dir_entry *top, *use_count;
-+ struct proc_dir_entry *clients = vchiq_clients_top();
-+ int pid = instance->pid;
-+
-+ snprintf(pidstr, sizeof(pidstr), "%d", pid);
-+ top = proc_mkdir(pidstr, clients);
-+ if (!top)
-+ goto fail_top;
-+
-+ use_count = create_proc_read_entry("use_count",
-+ 0444, top,
-+ proc_read_use_count,
-+ instance);
-+ if (!use_count)
-+ goto fail_use_count;
-+
-+ instance->proc_entry = top;
-+
-+ return 0;
-+
-+fail_use_count:
-+ remove_proc_entry(top->name, clients);
-+fail_top:
-+ return -ENOMEM;
-+#endif
-+}
-+
-+static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance)
-+{
-+#if 0
-+ struct proc_dir_entry *clients = vchiq_clients_top();
-+ remove_proc_entry("use_count", instance->proc_entry);
-+ remove_proc_entry(instance->proc_entry->name, clients);
-+#endif
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_exit - called when the module is unloaded.
-+*
-+***************************************************************************/
-+
-+static void __exit
-+vchiq_exit(void)
-+{
-+ vchiq_platform_exit(&g_state);
-+ device_destroy(vchiq_class, vchiq_devid);
-+ class_destroy(vchiq_class);
-+ cdev_del(&vchiq_cdev);
-+ unregister_chrdev_region(vchiq_devid, 1);
-+}
-+
-+module_init(vchiq_init);
-+module_exit(vchiq_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Broadcom Corporation");
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,212 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_ARM_H
-+#define VCHIQ_ARM_H
-+
-+#include <linux/mutex.h>
-+#include <linux/semaphore.h>
-+#include <linux/atomic.h>
-+#include "vchiq_core.h"
-+
-+
-+enum vc_suspend_status {
-+ VC_SUSPEND_FORCE_CANCELED = -3, /* Force suspend canceled, too busy */
-+ VC_SUSPEND_REJECTED = -2, /* Videocore rejected suspend request */
-+ VC_SUSPEND_FAILED = -1, /* Videocore suspend failed */
-+ VC_SUSPEND_IDLE = 0, /* VC active, no suspend actions */
-+ VC_SUSPEND_REQUESTED, /* User has requested suspend */
-+ VC_SUSPEND_IN_PROGRESS, /* Slot handler has recvd suspend request */
-+ VC_SUSPEND_SUSPENDED /* Videocore suspend succeeded */
-+};
-+
-+enum vc_resume_status {
-+ VC_RESUME_FAILED = -1, /* Videocore resume failed */
-+ VC_RESUME_IDLE = 0, /* VC suspended, no resume actions */
-+ VC_RESUME_REQUESTED, /* User has requested resume */
-+ VC_RESUME_IN_PROGRESS, /* Slot handler has received resume request */
-+ VC_RESUME_RESUMED /* Videocore resumed successfully (active) */
-+};
-+
-+
-+enum USE_TYPE_E {
-+ USE_TYPE_SERVICE,
-+ USE_TYPE_SERVICE_NO_RESUME,
-+ USE_TYPE_VCHIQ
-+};
-+
-+
-+
-+typedef struct vchiq_arm_state_struct {
-+ /* Keepalive-related data */
-+ struct task_struct *ka_thread;
-+ struct completion ka_evt;
-+ atomic_t ka_use_count;
-+ atomic_t ka_use_ack_count;
-+ atomic_t ka_release_count;
-+
-+ struct completion vc_suspend_complete;
-+ struct completion vc_resume_complete;
-+
-+ rwlock_t susp_res_lock;
-+ enum vc_suspend_status vc_suspend_state;
-+ enum vc_resume_status vc_resume_state;
-+
-+ unsigned int wake_address;
-+
-+ struct timer_list suspend_timer;
-+ int suspend_timer_timeout;
-+ int suspend_timer_running;
-+
-+ /* Global use count for videocore.
-+ ** This is equal to the sum of the use counts for all services. When
-+ ** this hits zero the videocore suspend procedure will be initiated.
-+ */
-+ int videocore_use_count;
-+
-+ /* Use count to track requests from videocore peer.
-+ ** This use count is not associated with a service, so needs to be
-+ ** tracked separately with the state.
-+ */
-+ int peer_use_count;
-+
-+ /* Flag to indicate whether resume is blocked. This happens when the
-+ ** ARM is suspending
-+ */
-+ struct completion resume_blocker;
-+ int resume_blocked;
-+ struct completion blocked_blocker;
-+ int blocked_count;
-+
-+ int autosuspend_override;
-+
-+ /* Flag to indicate that the first vchiq connect has made it through.
-+ ** This means that both sides should be fully ready, and we should
-+ ** be able to suspend after this point.
-+ */
-+ int first_connect;
-+
-+ unsigned long long suspend_start_time;
-+ unsigned long long sleep_start_time;
-+ unsigned long long resume_start_time;
-+ unsigned long long last_wake_time;
-+
-+} VCHIQ_ARM_STATE_T;
-+
-+extern int vchiq_arm_log_level;
-+extern int vchiq_susp_log_level;
-+
-+extern int __init
-+vchiq_platform_init(VCHIQ_STATE_T *state);
-+
-+extern void __exit
-+vchiq_platform_exit(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATE_T *
-+vchiq_get_state(void);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_vcsuspend(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_force_suspend(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_arm_allow_resume(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_vcresume(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state);
-+
-+extern int
-+vchiq_check_resume(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_check_suspend(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_check_service(VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_platform_suspend(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_platform_videocore_wanted(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_platform_use_suspend_timer(void);
-+
-+extern void
-+vchiq_dump_platform_use_state(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_dump_service_use_state(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_ARM_STATE_T*
-+vchiq_platform_get_arm_state(VCHIQ_STATE_T *state);
-+
-+extern int
-+vchiq_videocore_wanted(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ enum USE_TYPE_E use_type);
-+extern VCHIQ_STATUS_T
-+vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service);
-+
-+void
-+set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_suspend_status new_state);
-+
-+void
-+set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
-+ enum vc_resume_status new_state);
-+
-+void
-+start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state);
-+
-+extern int vchiq_proc_init(void);
-+extern void vchiq_proc_deinit(void);
-+extern struct proc_dir_entry *vchiq_proc_top(void);
-+extern struct proc_dir_entry *vchiq_clients_top(void);
-+
-+
-+#endif /* VCHIQ_ARM_H */
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_build_info.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,37 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+const char *vchiq_get_build_hostname(void);
-+const char *vchiq_get_build_version(void);
-+const char *vchiq_get_build_time(void);
-+const char *vchiq_get_build_date(void);
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,60 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_CFG_H
-+#define VCHIQ_CFG_H
-+
-+#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I')
-+/* The version of VCHIQ - change with any non-trivial change */
-+#define VCHIQ_VERSION 6
-+/* The minimum compatible version - update to match VCHIQ_VERSION with any
-+** incompatible change */
-+#define VCHIQ_VERSION_MIN 3
-+
-+#define VCHIQ_MAX_STATES 1
-+#define VCHIQ_MAX_SERVICES 4096
-+#define VCHIQ_MAX_SLOTS 128
-+#define VCHIQ_MAX_SLOTS_PER_SIDE 64
-+
-+#define VCHIQ_NUM_CURRENT_BULKS 32
-+#define VCHIQ_NUM_SERVICE_BULKS 4
-+
-+#ifndef VCHIQ_ENABLE_DEBUG
-+#define VCHIQ_ENABLE_DEBUG 1
-+#endif
-+
-+#ifndef VCHIQ_ENABLE_STATS
-+#define VCHIQ_ENABLE_STATS 1
-+#endif
-+
-+#endif /* VCHIQ_CFG_H */
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,119 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include "vchiq_connected.h"
-+#include "vchiq_core.h"
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+
-+#define MAX_CALLBACKS 10
-+
-+static int g_connected;
-+static int g_num_deferred_callbacks;
-+static VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[MAX_CALLBACKS];
-+static int g_once_init;
-+static struct mutex g_connected_mutex;
-+
-+/****************************************************************************
-+*
-+* Function to initialize our lock.
-+*
-+***************************************************************************/
-+
-+static void connected_init(void)
-+{
-+ if (!g_once_init) {
-+ mutex_init(&g_connected_mutex);
-+ g_once_init = 1;
-+ }
-+}
-+
-+/****************************************************************************
-+*
-+* This function is used to defer initialization until the vchiq stack is
-+* initialized. If the stack is already initialized, then the callback will
-+* be made immediately, otherwise it will be deferred until
-+* vchiq_call_connected_callbacks is called.
-+*
-+***************************************************************************/
-+
-+void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
-+{
-+ connected_init();
-+
-+ if (mutex_lock_interruptible(&g_connected_mutex) != 0)
-+ return;
-+
-+ if (g_connected)
-+ /* We're already connected. Call the callback immediately. */
-+
-+ callback();
-+ else {
-+ if (g_num_deferred_callbacks >= MAX_CALLBACKS)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "There already %d callback registered - "
-+ "please increase MAX_CALLBACKS",
-+ g_num_deferred_callbacks);
-+ else {
-+ g_deferred_callback[g_num_deferred_callbacks] =
-+ callback;
-+ g_num_deferred_callbacks++;
-+ }
-+ }
-+ mutex_unlock(&g_connected_mutex);
-+}
-+
-+/****************************************************************************
-+*
-+* This function is called by the vchiq stack once it has been connected to
-+* the videocore and clients can start to use the stack.
-+*
-+***************************************************************************/
-+
-+void vchiq_call_connected_callbacks(void)
-+{
-+ int i;
-+
-+ connected_init();
-+
-+ if (mutex_lock_interruptible(&g_connected_mutex) != 0)
-+ return;
-+
-+ for (i = 0; i < g_num_deferred_callbacks; i++)
-+ g_deferred_callback[i]();
-+
-+ g_num_deferred_callbacks = 0;
-+ g_connected = 1;
-+ mutex_unlock(&g_connected_mutex);
-+}
-+EXPORT_SYMBOL(vchiq_add_connected_callback);
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,50 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_CONNECTED_H
-+#define VCHIQ_CONNECTED_H
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+
-+/* ---- Constants and Types ---------------------------------------------- */
-+
-+typedef void (*VCHIQ_CONNECTED_CALLBACK_T)(void);
-+
-+/* ---- Variable Externs ------------------------------------------------- */
-+
-+/* ---- Function Prototypes ---------------------------------------------- */
-+
-+void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback);
-+void vchiq_call_connected_callbacks(void);
-+
-+#endif /* VCHIQ_CONNECTED_H */
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,3824 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include "vchiq_core.h"
-+
-+#define VCHIQ_SLOT_HANDLER_STACK 8192
-+
-+#define HANDLE_STATE_SHIFT 12
-+
-+#define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index))
-+#define SLOT_DATA_FROM_INDEX(state, index) (state->slot_data + (index))
-+#define SLOT_INDEX_FROM_DATA(state, data) \
-+ (((unsigned int)((char *)data - (char *)state->slot_data)) / \
-+ VCHIQ_SLOT_SIZE)
-+#define SLOT_INDEX_FROM_INFO(state, info) \
-+ ((unsigned int)(info - state->slot_info))
-+#define SLOT_QUEUE_INDEX_FROM_POS(pos) \
-+ ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE))
-+
-+
-+#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
-+
-+
-+struct vchiq_open_payload {
-+ int fourcc;
-+ int client_id;
-+ short version;
-+ short version_min;
-+};
-+
-+struct vchiq_openack_payload {
-+ short version;
-+};
-+
-+/* we require this for consistency between endpoints */
-+vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8);
-+vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T)));
-+vchiq_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS));
-+vchiq_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS));
-+vchiq_static_assert(IS_POW2(VCHIQ_MAX_SERVICES));
-+vchiq_static_assert(VCHIQ_VERSION >= VCHIQ_VERSION_MIN);
-+
-+/* Run time control of log level, based on KERN_XXX level. */
-+int vchiq_core_log_level = VCHIQ_LOG_DEFAULT;
-+int vchiq_core_msg_log_level = VCHIQ_LOG_DEFAULT;
-+int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT;
-+
-+static atomic_t pause_bulks_count = ATOMIC_INIT(0);
-+
-+static DEFINE_SPINLOCK(service_spinlock);
-+DEFINE_SPINLOCK(bulk_waiter_spinlock);
-+DEFINE_SPINLOCK(quota_spinlock);
-+
-+VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
-+static unsigned int handle_seq;
-+
-+static const char *const srvstate_names[] = {
-+ "FREE",
-+ "HIDDEN",
-+ "LISTENING",
-+ "OPENING",
-+ "OPEN",
-+ "OPENSYNC",
-+ "CLOSESENT",
-+ "CLOSERECVD",
-+ "CLOSEWAIT",
-+ "CLOSED"
-+};
-+
-+static const char *const reason_names[] = {
-+ "SERVICE_OPENED",
-+ "SERVICE_CLOSED",
-+ "MESSAGE_AVAILABLE",
-+ "BULK_TRANSMIT_DONE",
-+ "BULK_RECEIVE_DONE",
-+ "BULK_TRANSMIT_ABORTED",
-+ "BULK_RECEIVE_ABORTED"
-+};
-+
-+static const char *const conn_state_names[] = {
-+ "DISCONNECTED",
-+ "CONNECTING",
-+ "CONNECTED",
-+ "PAUSING",
-+ "PAUSE_SENT",
-+ "PAUSED",
-+ "RESUMING",
-+ "PAUSE_TIMEOUT",
-+ "RESUME_TIMEOUT"
-+};
-+
-+
-+static void
-+release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header);
-+
-+static const char *msg_type_str(unsigned int msg_type)
-+{
-+ switch (msg_type) {
-+ case VCHIQ_MSG_PADDING: return "PADDING";
-+ case VCHIQ_MSG_CONNECT: return "CONNECT";
-+ case VCHIQ_MSG_OPEN: return "OPEN";
-+ case VCHIQ_MSG_OPENACK: return "OPENACK";
-+ case VCHIQ_MSG_CLOSE: return "CLOSE";
-+ case VCHIQ_MSG_DATA: return "DATA";
-+ case VCHIQ_MSG_BULK_RX: return "BULK_RX";
-+ case VCHIQ_MSG_BULK_TX: return "BULK_TX";
-+ case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE";
-+ case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE";
-+ case VCHIQ_MSG_PAUSE: return "PAUSE";
-+ case VCHIQ_MSG_RESUME: return "RESUME";
-+ case VCHIQ_MSG_REMOTE_USE: return "REMOTE_USE";
-+ case VCHIQ_MSG_REMOTE_RELEASE: return "REMOTE_RELEASE";
-+ case VCHIQ_MSG_REMOTE_USE_ACTIVE: return "REMOTE_USE_ACTIVE";
-+ }
-+ return "???";
-+}
-+
-+static inline void
-+vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate)
-+{
-+ vchiq_log_info(vchiq_core_log_level, "%d: srv:%d %s->%s",
-+ service->state->id, service->localport,
-+ srvstate_names[service->srvstate],
-+ srvstate_names[newstate]);
-+ service->srvstate = newstate;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service;
-+
-+ spin_lock(&service_spinlock);
-+ service = handle_to_service(handle);
-+ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (service->handle == handle)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid service handle 0x%x", handle);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_service_by_port(VCHIQ_STATE_T *state, int localport)
-+{
-+ VCHIQ_SERVICE_T *service = NULL;
-+ if ((unsigned int)localport <= VCHIQ_PORT_MAX) {
-+ spin_lock(&service_spinlock);
-+ service = state->services[localport];
-+ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+ }
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid port %d", localport);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+find_service_for_instance(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_SERVICE_HANDLE_T handle) {
-+ VCHIQ_SERVICE_T *service;
-+
-+ spin_lock(&service_spinlock);
-+ service = handle_to_service(handle);
-+ if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (service->handle == handle) &&
-+ (service->instance == instance)) {
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ } else
-+ service = NULL;
-+ spin_unlock(&service_spinlock);
-+
-+ if (!service)
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Invalid service handle 0x%x", handle);
-+
-+ return service;
-+}
-+
-+VCHIQ_SERVICE_T *
-+next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
-+ int *pidx)
-+{
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int idx = *pidx;
-+
-+ spin_lock(&service_spinlock);
-+ while (idx < state->unused_service) {
-+ VCHIQ_SERVICE_T *srv = state->services[idx++];
-+ if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (srv->instance == instance)) {
-+ service = srv;
-+ BUG_ON(service->ref_count == 0);
-+ service->ref_count++;
-+ break;
-+ }
-+ }
-+ spin_unlock(&service_spinlock);
-+
-+ *pidx = idx;
-+
-+ return service;
-+}
-+
-+void
-+lock_service(VCHIQ_SERVICE_T *service)
-+{
-+ spin_lock(&service_spinlock);
-+ BUG_ON(!service || (service->ref_count == 0));
-+ if (service)
-+ service->ref_count++;
-+ spin_unlock(&service_spinlock);
-+}
-+
-+void
-+unlock_service(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ spin_lock(&service_spinlock);
-+ BUG_ON(!service || (service->ref_count == 0));
-+ if (service && service->ref_count) {
-+ service->ref_count--;
-+ if (!service->ref_count) {
-+ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
-+ state->services[service->localport] = NULL;
-+ } else
-+ service = NULL;
-+ }
-+ spin_unlock(&service_spinlock);
-+
-+ if (service && service->userdata_term)
-+ service->userdata_term(service->base.userdata);
-+
-+ kfree(service);
-+}
-+
-+int
-+vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ int id;
-+
-+ id = service ? service->client_id : 0;
-+ if (service)
-+ unlock_service(service);
-+
-+ return id;
-+}
-+
-+void *
-+vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service = handle_to_service(handle);
-+
-+ return service ? service->base.userdata : NULL;
-+}
-+
-+int
-+vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_SERVICE_T *service = handle_to_service(handle);
-+
-+ return service ? service->base.fourcc : 0;
-+}
-+
-+static void
-+mark_service_closing_internal(VCHIQ_SERVICE_T *service, int sh_thread)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ VCHIQ_SERVICE_QUOTA_T *service_quota;
-+
-+ service->closing = 1;
-+
-+ /* Synchronise with other threads. */
-+ mutex_lock(&state->recycle_mutex);
-+ mutex_unlock(&state->recycle_mutex);
-+ if (!sh_thread || (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT)) {
-+ /* If we're pausing then the slot_mutex is held until resume
-+ * by the slot handler. Therefore don't try to acquire this
-+ * mutex if we're the slot handler and in the pause sent state.
-+ * We don't need to in this case anyway. */
-+ mutex_lock(&state->slot_mutex);
-+ mutex_unlock(&state->slot_mutex);
-+ }
-+
-+ /* Unblock any sending thread. */
-+ service_quota = &state->service_quotas[service->localport];
-+ up(&service_quota->quota_event);
-+}
-+
-+static void
-+mark_service_closing(VCHIQ_SERVICE_T *service)
-+{
-+ mark_service_closing_internal(service, 0);
-+}
-+
-+static inline VCHIQ_STATUS_T
-+make_service_callback(VCHIQ_SERVICE_T *service, VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header, void *bulk_userdata)
-+{
-+ VCHIQ_STATUS_T status;
-+ vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %x, %x)",
-+ service->state->id, service->localport, reason_names[reason],
-+ (unsigned int)header, (unsigned int)bulk_userdata);
-+ status = service->base.callback(reason, header, service->handle,
-+ bulk_userdata);
-+ if (status == VCHIQ_ERROR) {
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: ignoring ERROR from callback to service %x",
-+ service->state->id, service->handle);
-+ status = VCHIQ_SUCCESS;
-+ }
-+ return status;
-+}
-+
-+inline void
-+vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
-+{
-+ VCHIQ_CONNSTATE_T oldstate = state->conn_state;
-+ vchiq_log_info(vchiq_core_log_level, "%d: %s->%s", state->id,
-+ conn_state_names[oldstate],
-+ conn_state_names[newstate]);
-+ state->conn_state = newstate;
-+ vchiq_platform_conn_state_changed(state, oldstate, newstate);
-+}
-+
-+static inline void
-+remote_event_create(REMOTE_EVENT_T *event)
-+{
-+ event->armed = 0;
-+ /* Don't clear the 'fired' flag because it may already have been set
-+ ** by the other side. */
-+ sema_init(event->event, 0);
-+}
-+
-+static inline void
-+remote_event_destroy(REMOTE_EVENT_T *event)
-+{
-+ (void)event;
-+}
-+
-+static inline int
-+remote_event_wait(REMOTE_EVENT_T *event)
-+{
-+ if (!event->fired) {
-+ event->armed = 1;
-+ dsb();
-+ if (!event->fired) {
-+ if (down_interruptible(event->event) != 0) {
-+ event->armed = 0;
-+ return 0;
-+ }
-+ }
-+ event->armed = 0;
-+ wmb();
-+ }
-+
-+ event->fired = 0;
-+ return 1;
-+}
-+
-+static inline void
-+remote_event_signal_local(REMOTE_EVENT_T *event)
-+{
-+ event->armed = 0;
-+ up(event->event);
-+}
-+
-+static inline void
-+remote_event_poll(REMOTE_EVENT_T *event)
-+{
-+ if (event->fired && event->armed)
-+ remote_event_signal_local(event);
-+}
-+
-+void
-+remote_event_pollall(VCHIQ_STATE_T *state)
-+{
-+ remote_event_poll(&state->local->sync_trigger);
-+ remote_event_poll(&state->local->sync_release);
-+ remote_event_poll(&state->local->trigger);
-+ remote_event_poll(&state->local->recycle);
-+}
-+
-+/* Round up message sizes so that any space at the end of a slot is always big
-+** enough for a header. This relies on header size being a power of two, which
-+** has been verified earlier by a static assertion. */
-+
-+static inline unsigned int
-+calc_stride(unsigned int size)
-+{
-+ /* Allow room for the header */
-+ size += sizeof(VCHIQ_HEADER_T);
-+
-+ /* Round up */
-+ return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T)
-+ - 1);
-+}
-+
-+/* Called by the slot handler thread */
-+static VCHIQ_SERVICE_T *
-+get_listening_service(VCHIQ_STATE_T *state, int fourcc)
-+{
-+ int i;
-+
-+ WARN_ON(fourcc == VCHIQ_FOURCC_INVALID);
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ if (service &&
-+ (service->public_fourcc == fourcc) &&
-+ ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-+ ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
-+ (service->remoteport == VCHIQ_PORT_FREE)))) {
-+ lock_service(service);
-+ return service;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+/* Called by the slot handler thread */
-+static VCHIQ_SERVICE_T *
-+get_connected_service(VCHIQ_STATE_T *state, unsigned int port)
-+{
-+ int i;
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN)
-+ && (service->remoteport == port)) {
-+ lock_service(service);
-+ return service;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+inline void
-+request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
-+{
-+ uint32_t value;
-+
-+ if (service) {
-+ do {
-+ value = atomic_read(&service->poll_flags);
-+ } while (atomic_cmpxchg(&service->poll_flags, value,
-+ value | (1 << poll_type)) != value);
-+
-+ do {
-+ value = atomic_read(&state->poll_services[
-+ service->localport>>5]);
-+ } while (atomic_cmpxchg(
-+ &state->poll_services[service->localport>>5],
-+ value, value | (1 << (service->localport & 0x1f)))
-+ != value);
-+ }
-+
-+ state->poll_needed = 1;
-+ wmb();
-+
-+ /* ... and ensure the slot handler runs. */
-+ remote_event_signal_local(&state->local->trigger);
-+}
-+
-+/* Called from queue_message, by the slot handler and application threads,
-+** with slot_mutex held */
-+static VCHIQ_HEADER_T *
-+reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking)
-+{
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ int tx_pos = state->local_tx_pos;
-+ int slot_space = VCHIQ_SLOT_SIZE - (tx_pos & VCHIQ_SLOT_MASK);
-+
-+ if (space > slot_space) {
-+ VCHIQ_HEADER_T *header;
-+ /* Fill the remaining space with padding */
-+ WARN_ON(state->tx_data == NULL);
-+ header = (VCHIQ_HEADER_T *)
-+ (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
-+ header->msgid = VCHIQ_MSGID_PADDING;
-+ header->size = slot_space - sizeof(VCHIQ_HEADER_T);
-+
-+ tx_pos += slot_space;
-+ }
-+
-+ /* If necessary, get the next slot. */
-+ if ((tx_pos & VCHIQ_SLOT_MASK) == 0) {
-+ int slot_index;
-+
-+ /* If there is no free slot... */
-+
-+ if (down_trylock(&state->slot_available_event) != 0) {
-+ /* ...wait for one. */
-+
-+ VCHIQ_STATS_INC(state, slot_stalls);
-+
-+ /* But first, flush through the last slot. */
-+ state->local_tx_pos = tx_pos;
-+ local->tx_pos = tx_pos;
-+ remote_event_signal(&state->remote->trigger);
-+
-+ if (!is_blocking ||
-+ (down_interruptible(
-+ &state->slot_available_event) != 0))
-+ return NULL; /* No space available */
-+ }
-+
-+ BUG_ON(tx_pos ==
-+ (state->slot_queue_available * VCHIQ_SLOT_SIZE));
-+
-+ slot_index = local->slot_queue[
-+ SLOT_QUEUE_INDEX_FROM_POS(tx_pos) &
-+ VCHIQ_SLOT_QUEUE_MASK];
-+ state->tx_data =
-+ (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
-+ }
-+
-+ state->local_tx_pos = tx_pos + space;
-+
-+ return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
-+}
-+
-+/* Called by the recycle thread. */
-+static void
-+process_free_queue(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
-+ int slot_queue_available;
-+
-+ /* Use a read memory barrier to ensure that any state that may have
-+ ** been modified by another thread is not masked by stale prefetched
-+ ** values. */
-+ rmb();
-+
-+ /* Find slots which have been freed by the other side, and return them
-+ ** to the available queue. */
-+ slot_queue_available = state->slot_queue_available;
-+
-+ while (slot_queue_available != local->slot_queue_recycle) {
-+ unsigned int pos;
-+ int slot_index = local->slot_queue[slot_queue_available++ &
-+ VCHIQ_SLOT_QUEUE_MASK];
-+ char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
-+ int data_found = 0;
-+
-+ vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%x %x %x",
-+ state->id, slot_index, (unsigned int)data,
-+ local->slot_queue_recycle, slot_queue_available);
-+
-+ /* Initialise the bitmask for services which have used this
-+ ** slot */
-+ BITSET_ZERO(service_found);
-+
-+ pos = 0;
-+
-+ while (pos < VCHIQ_SLOT_SIZE) {
-+ VCHIQ_HEADER_T *header =
-+ (VCHIQ_HEADER_T *)(data + pos);
-+ int msgid = header->msgid;
-+ if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA) {
-+ int port = VCHIQ_MSG_SRCPORT(msgid);
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &state->service_quotas[port];
-+ int count;
-+ spin_lock(&quota_spinlock);
-+ count = service_quota->message_use_count;
-+ if (count > 0)
-+ service_quota->message_use_count =
-+ count - 1;
-+ spin_unlock(&quota_spinlock);
-+
-+ if (count == service_quota->message_quota)
-+ /* Signal the service that it
-+ ** has dropped below its quota
-+ */
-+ up(&service_quota->quota_event);
-+ else if (count == 0) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "service %d "
-+ "message_use_count=%d "
-+ "(header %x, msgid %x, "
-+ "header->msgid %x, "
-+ "header->size %x)",
-+ port,
-+ service_quota->
-+ message_use_count,
-+ (unsigned int)header, msgid,
-+ header->msgid,
-+ header->size);
-+ WARN(1, "invalid message use count\n");
-+ }
-+ if (!BITSET_IS_SET(service_found, port)) {
-+ /* Set the found bit for this service */
-+ BITSET_SET(service_found, port);
-+
-+ spin_lock(&quota_spinlock);
-+ count = service_quota->slot_use_count;
-+ if (count > 0)
-+ service_quota->slot_use_count =
-+ count - 1;
-+ spin_unlock(&quota_spinlock);
-+
-+ if (count > 0) {
-+ /* Signal the service in case
-+ ** it has dropped below its
-+ ** quota */
-+ up(&service_quota->quota_event);
-+ vchiq_log_trace(
-+ vchiq_core_log_level,
-+ "%d: pfq:%d %x@%x - "
-+ "slot_use->%d",
-+ state->id, port,
-+ header->size,
-+ (unsigned int)header,
-+ count - 1);
-+ } else {
-+ vchiq_log_error(
-+ vchiq_core_log_level,
-+ "service %d "
-+ "slot_use_count"
-+ "=%d (header %x"
-+ ", msgid %x, "
-+ "header->msgid"
-+ " %x, header->"
-+ "size %x)",
-+ port, count,
-+ (unsigned int)header,
-+ msgid,
-+ header->msgid,
-+ header->size);
-+ WARN(1, "bad slot use count\n");
-+ }
-+ }
-+
-+ data_found = 1;
-+ }
-+
-+ pos += calc_stride(header->size);
-+ if (pos > VCHIQ_SLOT_SIZE) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "pfq - pos %x: header %x, msgid %x, "
-+ "header->msgid %x, header->size %x",
-+ pos, (unsigned int)header, msgid,
-+ header->msgid, header->size);
-+ WARN(1, "invalid slot position\n");
-+ }
-+ }
-+
-+ if (data_found) {
-+ int count;
-+ spin_lock(&quota_spinlock);
-+ count = state->data_use_count;
-+ if (count > 0)
-+ state->data_use_count =
-+ count - 1;
-+ spin_unlock(&quota_spinlock);
-+ if (count == state->data_quota)
-+ up(&state->data_quota_event);
-+ }
-+
-+ state->slot_queue_available = slot_queue_available;
-+ up(&state->slot_available_event);
-+ }
-+}
-+
-+/* Called by the slot handler and application threads */
-+static VCHIQ_STATUS_T
-+queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ int msgid, const VCHIQ_ELEMENT_T *elements,
-+ int count, int size, int is_blocking)
-+{
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
-+ VCHIQ_HEADER_T *header;
-+ int type = VCHIQ_MSG_TYPE(msgid);
-+
-+ unsigned int stride;
-+
-+ local = state->local;
-+
-+ stride = calc_stride(size);
-+
-+ WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
-+
-+ if ((type != VCHIQ_MSG_RESUME) &&
-+ (mutex_lock_interruptible(&state->slot_mutex) != 0))
-+ return VCHIQ_RETRY;
-+
-+ if (type == VCHIQ_MSG_DATA) {
-+ int tx_end_index;
-+
-+ BUG_ON(!service);
-+
-+ if (service->closing) {
-+ /* The service has been closed */
-+ mutex_unlock(&state->slot_mutex);
-+ return VCHIQ_ERROR;
-+ }
-+
-+ service_quota = &state->service_quotas[service->localport];
-+
-+ spin_lock(&quota_spinlock);
-+
-+ /* Ensure this service doesn't use more than its quota of
-+ ** messages or slots */
-+ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
-+ state->local_tx_pos + stride - 1);
-+
-+ /* Ensure data messages don't use more than their quota of
-+ ** slots */
-+ while ((tx_end_index != state->previous_data_index) &&
-+ (state->data_use_count == state->data_quota)) {
-+ VCHIQ_STATS_INC(state, data_stalls);
-+ spin_unlock(&quota_spinlock);
-+ mutex_unlock(&state->slot_mutex);
-+
-+ if (down_interruptible(&state->data_quota_event)
-+ != 0)
-+ return VCHIQ_RETRY;
-+
-+ mutex_lock(&state->slot_mutex);
-+ spin_lock(&quota_spinlock);
-+ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
-+ state->local_tx_pos + stride - 1);
-+ if ((tx_end_index == state->previous_data_index) ||
-+ (state->data_use_count < state->data_quota)) {
-+ /* Pass the signal on to other waiters */
-+ up(&state->data_quota_event);
-+ break;
-+ }
-+ }
-+
-+ while ((service_quota->message_use_count ==
-+ service_quota->message_quota) ||
-+ ((tx_end_index != service_quota->previous_tx_index) &&
-+ (service_quota->slot_use_count ==
-+ service_quota->slot_quota))) {
-+ spin_unlock(&quota_spinlock);
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: qm:%d %s,%x - quota stall "
-+ "(msg %d, slot %d)",
-+ state->id, service->localport,
-+ msg_type_str(type), size,
-+ service_quota->message_use_count,
-+ service_quota->slot_use_count);
-+ VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
-+ mutex_unlock(&state->slot_mutex);
-+ if (down_interruptible(&service_quota->quota_event)
-+ != 0)
-+ return VCHIQ_RETRY;
-+ if (service->closing)
-+ return VCHIQ_ERROR;
-+ if (mutex_lock_interruptible(&state->slot_mutex) != 0)
-+ return VCHIQ_RETRY;
-+ if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
-+ /* The service has been closed */
-+ mutex_unlock(&state->slot_mutex);
-+ return VCHIQ_ERROR;
-+ }
-+ spin_lock(&quota_spinlock);
-+ tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(
-+ state->local_tx_pos + stride - 1);
-+ }
-+
-+ spin_unlock(&quota_spinlock);
-+ }
-+
-+ header = reserve_space(state, stride, is_blocking);
-+
-+ if (!header) {
-+ if (service)
-+ VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
-+ mutex_unlock(&state->slot_mutex);
-+ return VCHIQ_RETRY;
-+ }
-+
-+ if (type == VCHIQ_MSG_DATA) {
-+ int i, pos;
-+ int tx_end_index;
-+ int slot_use_count;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: qm %s@%x,%x (%d->%d)",
-+ state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+
-+ BUG_ON(!service);
-+
-+ for (i = 0, pos = 0; i < (unsigned int)count;
-+ pos += elements[i++].size)
-+ if (elements[i].size) {
-+ if (vchiq_copy_from_user
-+ (header->data + pos, elements[i].data,
-+ (size_t) elements[i].size) !=
-+ VCHIQ_SUCCESS) {
-+ mutex_unlock(&state->slot_mutex);
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ error_count);
-+ return VCHIQ_ERROR;
-+ }
-+ if (i == 0) {
-+ if (vchiq_core_msg_log_level >=
-+ VCHIQ_LOG_INFO)
-+ vchiq_log_dump_mem("Sent", 0,
-+ header->data + pos,
-+ min(64u,
-+ elements[0].size));
-+ }
-+ }
-+
-+ spin_lock(&quota_spinlock);
-+ service_quota->message_use_count++;
-+
-+ tx_end_index =
-+ SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1);
-+
-+ /* If this transmission can't fit in the last slot used by any
-+ ** service, the data_use_count must be increased. */
-+ if (tx_end_index != state->previous_data_index) {
-+ state->previous_data_index = tx_end_index;
-+ state->data_use_count++;
-+ }
-+
-+ /* If this isn't the same slot last used by this service,
-+ ** the service's slot_use_count must be increased. */
-+ if (tx_end_index != service_quota->previous_tx_index) {
-+ service_quota->previous_tx_index = tx_end_index;
-+ slot_use_count = ++service_quota->slot_use_count;
-+ } else {
-+ slot_use_count = 0;
-+ }
-+
-+ spin_unlock(&quota_spinlock);
-+
-+ if (slot_use_count)
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: qm:%d %s,%x - slot_use->%d (hdr %p)",
-+ state->id, service->localport,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)), size,
-+ slot_use_count, header);
-+
-+ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
-+ } else {
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: qm %s@%x,%x (%d->%d)", state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+ if (size != 0) {
-+ WARN_ON(!((count == 1) && (size == elements[0].size)));
-+ memcpy(header->data, elements[0].data,
-+ elements[0].size);
-+ }
-+ VCHIQ_STATS_INC(state, ctrl_tx_count);
-+ }
-+
-+ header->msgid = msgid;
-+ header->size = size;
-+
-+ {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ VCHIQ_MSG_TYPE(msgid),
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid),
-+ size);
-+ }
-+
-+ /* Make sure the new header is visible to the peer. */
-+ wmb();
-+
-+ /* Make the new tx_pos visible to the peer. */
-+ local->tx_pos = state->local_tx_pos;
-+ wmb();
-+
-+ if (service && (type == VCHIQ_MSG_CLOSE))
-+ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
-+
-+ if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
-+ mutex_unlock(&state->slot_mutex);
-+
-+ remote_event_signal(&state->remote->trigger);
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+/* Called by the slot handler and application threads */
-+static VCHIQ_STATUS_T
-+queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
-+ int msgid, const VCHIQ_ELEMENT_T *elements,
-+ int count, int size, int is_blocking)
-+{
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_HEADER_T *header;
-+
-+ local = state->local;
-+
-+ if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
-+ (mutex_lock_interruptible(&state->sync_mutex) != 0))
-+ return VCHIQ_RETRY;
-+
-+ remote_event_wait(&local->sync_release);
-+
-+ rmb();
-+
-+ header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
-+ local->slot_sync);
-+
-+ {
-+ int oldmsgid = header->msgid;
-+ if (oldmsgid != VCHIQ_MSGID_PADDING)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: qms - msgid %x, not PADDING",
-+ state->id, oldmsgid);
-+ }
-+
-+ if (service) {
-+ int i, pos;
-+
-+ vchiq_log_info(vchiq_sync_log_level,
-+ "%d: qms %s@%x,%x (%d->%d)", state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+
-+ for (i = 0, pos = 0; i < (unsigned int)count;
-+ pos += elements[i++].size)
-+ if (elements[i].size) {
-+ if (vchiq_copy_from_user
-+ (header->data + pos, elements[i].data,
-+ (size_t) elements[i].size) !=
-+ VCHIQ_SUCCESS) {
-+ mutex_unlock(&state->sync_mutex);
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ error_count);
-+ return VCHIQ_ERROR;
-+ }
-+ if (i == 0) {
-+ if (vchiq_sync_log_level >=
-+ VCHIQ_LOG_TRACE)
-+ vchiq_log_dump_mem("Sent Sync",
-+ 0, header->data + pos,
-+ min(64u,
-+ elements[0].size));
-+ }
-+ }
-+
-+ VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
-+ } else {
-+ vchiq_log_info(vchiq_sync_log_level,
-+ "%d: qms %s@%x,%x (%d->%d)", state->id,
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ (unsigned int)header, size,
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid));
-+ if (size != 0) {
-+ WARN_ON(!((count == 1) && (size == elements[0].size)));
-+ memcpy(header->data, elements[0].data,
-+ elements[0].size);
-+ }
-+ VCHIQ_STATS_INC(state, ctrl_tx_count);
-+ }
-+
-+ header->size = size;
-+ header->msgid = msgid;
-+
-+ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+
-+ vchiq_log_trace(vchiq_sync_log_level,
-+ "Sent Sync Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
-+ msg_type_str(VCHIQ_MSG_TYPE(msgid)),
-+ VCHIQ_MSG_TYPE(msgid),
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ VCHIQ_MSG_SRCPORT(msgid),
-+ VCHIQ_MSG_DSTPORT(msgid),
-+ size);
-+ }
-+
-+ /* Make sure the new header is visible to the peer. */
-+ wmb();
-+
-+ remote_event_signal(&state->remote->sync_trigger);
-+
-+ if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
-+ mutex_unlock(&state->sync_mutex);
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+static inline void
-+claim_slot(VCHIQ_SLOT_INFO_T *slot)
-+{
-+ slot->use_count++;
-+}
-+
-+static void
-+release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info,
-+ VCHIQ_HEADER_T *header, VCHIQ_SERVICE_T *service)
-+{
-+ int release_count;
-+
-+ mutex_lock(&state->recycle_mutex);
-+
-+ if (header) {
-+ int msgid = header->msgid;
-+ if (((msgid & VCHIQ_MSGID_CLAIMED) == 0) ||
-+ (service && service->closing)) {
-+ mutex_unlock(&state->recycle_mutex);
-+ return;
-+ }
-+
-+ /* Rewrite the message header to prevent a double
-+ ** release */
-+ header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
-+ }
-+
-+ release_count = slot_info->release_count;
-+ slot_info->release_count = ++release_count;
-+
-+ if (release_count == slot_info->use_count) {
-+ int slot_queue_recycle;
-+ /* Add to the freed queue */
-+
-+ /* A read barrier is necessary here to prevent speculative
-+ ** fetches of remote->slot_queue_recycle from overtaking the
-+ ** mutex. */
-+ rmb();
-+
-+ slot_queue_recycle = state->remote->slot_queue_recycle;
-+ state->remote->slot_queue[slot_queue_recycle &
-+ VCHIQ_SLOT_QUEUE_MASK] =
-+ SLOT_INDEX_FROM_INFO(state, slot_info);
-+ state->remote->slot_queue_recycle = slot_queue_recycle + 1;
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: release_slot %d - recycle->%x",
-+ state->id, SLOT_INDEX_FROM_INFO(state, slot_info),
-+ state->remote->slot_queue_recycle);
-+
-+ /* A write barrier is necessary, but remote_event_signal
-+ ** contains one. */
-+ remote_event_signal(&state->remote->recycle);
-+ }
-+
-+ mutex_unlock(&state->recycle_mutex);
-+}
-+
-+/* Called by the slot handler - don't hold the bulk mutex */
-+static VCHIQ_STATUS_T
-+notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue,
-+ int retry_poll)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: nb:%d %cx - p=%x rn=%x r=%x",
-+ service->state->id, service->localport,
-+ (queue == &service->bulk_tx) ? 't' : 'r',
-+ queue->process, queue->remote_notify, queue->remove);
-+
-+ if (service->state->is_master) {
-+ while (queue->remote_notify != queue->process) {
-+ VCHIQ_BULK_T *bulk =
-+ &queue->bulks[BULK_INDEX(queue->remote_notify)];
-+ int msgtype = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
-+ VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE;
-+ int msgid = VCHIQ_MAKE_MSG(msgtype, service->localport,
-+ service->remoteport);
-+ VCHIQ_ELEMENT_T element = { &bulk->actual, 4 };
-+ /* Only reply to non-dummy bulk requests */
-+ if (bulk->remote_data) {
-+ status = queue_message(service->state, NULL,
-+ msgid, &element, 1, 4, 0);
-+ if (status != VCHIQ_SUCCESS)
-+ break;
-+ }
-+ queue->remote_notify++;
-+ }
-+ } else {
-+ queue->remote_notify = queue->process;
-+ }
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ while (queue->remove != queue->remote_notify) {
-+ VCHIQ_BULK_T *bulk =
-+ &queue->bulks[BULK_INDEX(queue->remove)];
-+
-+ /* Only generate callbacks for non-dummy bulk
-+ ** requests, and non-terminated services */
-+ if (bulk->data && service->instance) {
-+ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) {
-+ if (bulk->dir == VCHIQ_BULK_TRANSMIT) {
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ bulk_tx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service,
-+ bulk_tx_bytes,
-+ bulk->actual);
-+ } else {
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ bulk_rx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service,
-+ bulk_rx_bytes,
-+ bulk->actual);
-+ }
-+ } else {
-+ VCHIQ_SERVICE_STATS_INC(service,
-+ bulk_aborted_count);
-+ }
-+ if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) {
-+ struct bulk_waiter *waiter;
-+ spin_lock(&bulk_waiter_spinlock);
-+ waiter = bulk->userdata;
-+ if (waiter) {
-+ waiter->actual = bulk->actual;
-+ up(&waiter->event);
-+ }
-+ spin_unlock(&bulk_waiter_spinlock);
-+ } else if (bulk->mode ==
-+ VCHIQ_BULK_MODE_CALLBACK) {
-+ VCHIQ_REASON_T reason = (bulk->dir ==
-+ VCHIQ_BULK_TRANSMIT) ?
-+ ((bulk->actual ==
-+ VCHIQ_BULK_ACTUAL_ABORTED) ?
-+ VCHIQ_BULK_TRANSMIT_ABORTED :
-+ VCHIQ_BULK_TRANSMIT_DONE) :
-+ ((bulk->actual ==
-+ VCHIQ_BULK_ACTUAL_ABORTED) ?
-+ VCHIQ_BULK_RECEIVE_ABORTED :
-+ VCHIQ_BULK_RECEIVE_DONE);
-+ status = make_service_callback(service,
-+ reason, NULL, bulk->userdata);
-+ if (status == VCHIQ_RETRY)
-+ break;
-+ }
-+ }
-+
-+ queue->remove++;
-+ up(&service->bulk_remove_event);
-+ }
-+ if (!retry_poll)
-+ status = VCHIQ_SUCCESS;
-+ }
-+
-+ if (status == VCHIQ_RETRY)
-+ request_poll(service->state, service,
-+ (queue == &service->bulk_tx) ?
-+ VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
-+
-+ return status;
-+}
-+
-+/* Called by the slot handler thread */
-+static void
-+poll_services(VCHIQ_STATE_T *state)
-+{
-+ int group, i;
-+
-+ for (group = 0; group < BITSET_SIZE(state->unused_service); group++) {
-+ uint32_t flags;
-+ flags = atomic_xchg(&state->poll_services[group], 0);
-+ for (i = 0; flags; i++) {
-+ if (flags & (1 << i)) {
-+ VCHIQ_SERVICE_T *service =
-+ find_service_by_port(state,
-+ (group<<5) + i);
-+ uint32_t service_flags;
-+ flags &= ~(1 << i);
-+ if (!service)
-+ continue;
-+ service_flags =
-+ atomic_xchg(&service->poll_flags, 0);
-+ if (service_flags &
-+ (1 << VCHIQ_POLL_REMOVE)) {
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: ps - remove %d<->%d",
-+ state->id, service->localport,
-+ service->remoteport);
-+
-+ /* Make it look like a client, because
-+ it must be removed and not left in
-+ the LISTENING state. */
-+ service->public_fourcc =
-+ VCHIQ_FOURCC_INVALID;
-+
-+ if (vchiq_close_service_internal(
-+ service, 0/*!close_recvd*/) !=
-+ VCHIQ_SUCCESS)
-+ request_poll(state, service,
-+ VCHIQ_POLL_REMOVE);
-+ } else if (service_flags &
-+ (1 << VCHIQ_POLL_TERMINATE)) {
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: ps - terminate %d<->%d",
-+ state->id, service->localport,
-+ service->remoteport);
-+ if (vchiq_close_service_internal(
-+ service, 0/*!close_recvd*/) !=
-+ VCHIQ_SUCCESS)
-+ request_poll(state, service,
-+ VCHIQ_POLL_TERMINATE);
-+ }
-+ if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY))
-+ notify_bulks(service,
-+ &service->bulk_tx,
-+ 1/*retry_poll*/);
-+ if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY))
-+ notify_bulks(service,
-+ &service->bulk_rx,
-+ 1/*retry_poll*/);
-+ unlock_service(service);
-+ }
-+ }
-+ }
-+}
-+
-+/* Called by the slot handler or application threads, holding the bulk mutex. */
-+static int
-+resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ int resolved = 0;
-+ int rc;
-+
-+ while ((queue->process != queue->local_insert) &&
-+ (queue->process != queue->remote_insert)) {
-+ VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: rb:%d %cx - li=%x ri=%x p=%x",
-+ state->id, service->localport,
-+ (queue == &service->bulk_tx) ? 't' : 'r',
-+ queue->local_insert, queue->remote_insert,
-+ queue->process);
-+
-+ WARN_ON(!((int)(queue->local_insert - queue->process) > 0));
-+ WARN_ON(!((int)(queue->remote_insert - queue->process) > 0));
-+
-+ rc = mutex_lock_interruptible(&state->bulk_transfer_mutex);
-+ if (rc != 0)
-+ break;
-+
-+ vchiq_transfer_bulk(bulk);
-+ mutex_unlock(&state->bulk_transfer_mutex);
-+
-+ if (vchiq_core_msg_log_level >= VCHIQ_LOG_INFO) {
-+ const char *header = (queue == &service->bulk_tx) ?
-+ "Send Bulk to" : "Recv Bulk from";
-+ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "%s %c%c%c%c d:%d len:%d %x<->%x",
-+ header,
-+ VCHIQ_FOURCC_AS_4CHARS(
-+ service->base.fourcc),
-+ service->remoteport,
-+ bulk->size,
-+ (unsigned int)bulk->data,
-+ (unsigned int)bulk->remote_data);
-+ else
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "%s %c%c%c%c d:%d ABORTED - tx len:%d,"
-+ " rx len:%d %x<->%x",
-+ header,
-+ VCHIQ_FOURCC_AS_4CHARS(
-+ service->base.fourcc),
-+ service->remoteport,
-+ bulk->size,
-+ bulk->remote_size,
-+ (unsigned int)bulk->data,
-+ (unsigned int)bulk->remote_data);
-+ }
-+
-+ vchiq_complete_bulk(bulk);
-+ queue->process++;
-+ resolved++;
-+ }
-+ return resolved;
-+}
-+
-+/* Called with the bulk_mutex held */
-+static void
-+abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
-+{
-+ int is_tx = (queue == &service->bulk_tx);
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: aob:%d %cx - li=%x ri=%x p=%x",
-+ service->state->id, service->localport, is_tx ? 't' : 'r',
-+ queue->local_insert, queue->remote_insert, queue->process);
-+
-+ WARN_ON(!((int)(queue->local_insert - queue->process) >= 0));
-+ WARN_ON(!((int)(queue->remote_insert - queue->process) >= 0));
-+
-+ while ((queue->process != queue->local_insert) ||
-+ (queue->process != queue->remote_insert)) {
-+ VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
-+
-+ if (queue->process == queue->remote_insert) {
-+ /* fabricate a matching dummy bulk */
-+ bulk->remote_data = NULL;
-+ bulk->remote_size = 0;
-+ queue->remote_insert++;
-+ }
-+
-+ if (queue->process != queue->local_insert) {
-+ vchiq_complete_bulk(bulk);
-+
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "%s %c%c%c%c d:%d ABORTED - tx len:%d, "
-+ "rx len:%d",
-+ is_tx ? "Send Bulk to" : "Recv Bulk from",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->remoteport,
-+ bulk->size,
-+ bulk->remote_size);
-+ } else {
-+ /* fabricate a matching dummy bulk */
-+ bulk->data = NULL;
-+ bulk->size = 0;
-+ bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
-+ bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT :
-+ VCHIQ_BULK_RECEIVE;
-+ queue->local_insert++;
-+ }
-+
-+ queue->process++;
-+ }
-+}
-+
-+/* Called from the slot handler thread */
-+static void
-+pause_bulks(VCHIQ_STATE_T *state)
-+{
-+ if (unlikely(atomic_inc_return(&pause_bulks_count) != 1)) {
-+ WARN_ON_ONCE(1);
-+ atomic_set(&pause_bulks_count, 1);
-+ return;
-+ }
-+
-+ /* Block bulk transfers from all services */
-+ mutex_lock(&state->bulk_transfer_mutex);
-+}
-+
-+/* Called from the slot handler thread */
-+static void
-+resume_bulks(VCHIQ_STATE_T *state)
-+{
-+ int i;
-+ if (unlikely(atomic_dec_return(&pause_bulks_count) != 0)) {
-+ WARN_ON_ONCE(1);
-+ atomic_set(&pause_bulks_count, 0);
-+ return;
-+ }
-+
-+ /* Allow bulk transfers from all services */
-+ mutex_unlock(&state->bulk_transfer_mutex);
-+
-+ if (state->deferred_bulks == 0)
-+ return;
-+
-+ /* Deal with any bulks which had to be deferred due to being in
-+ * paused state. Don't try to match up to number of deferred bulks
-+ * in case we've had something come and close the service in the
-+ * interim - just process all bulk queues for all services */
-+ vchiq_log_info(vchiq_core_log_level, "%s: processing %d deferred bulks",
-+ __func__, state->deferred_bulks);
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = state->services[i];
-+ int resolved_rx = 0;
-+ int resolved_tx = 0;
-+ if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
-+ continue;
-+
-+ mutex_lock(&service->bulk_mutex);
-+ resolved_rx = resolve_bulks(service, &service->bulk_rx);
-+ resolved_tx = resolve_bulks(service, &service->bulk_tx);
-+ mutex_unlock(&service->bulk_mutex);
-+ if (resolved_rx)
-+ notify_bulks(service, &service->bulk_rx, 1);
-+ if (resolved_tx)
-+ notify_bulks(service, &service->bulk_tx, 1);
-+ }
-+ state->deferred_bulks = 0;
-+}
-+
-+static int
-+parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
-+{
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int msgid, size;
-+ int type;
-+ unsigned int localport, remoteport;
-+
-+ msgid = header->msgid;
-+ size = header->size;
-+ type = VCHIQ_MSG_TYPE(msgid);
-+ localport = VCHIQ_MSG_DSTPORT(msgid);
-+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
-+ if (size >= sizeof(struct vchiq_open_payload)) {
-+ const struct vchiq_open_payload *payload =
-+ (struct vchiq_open_payload *)header->data;
-+ unsigned int fourcc;
-+
-+ fourcc = payload->fourcc;
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs OPEN@%x (%d->'%c%c%c%c')",
-+ state->id, (unsigned int)header,
-+ localport,
-+ VCHIQ_FOURCC_AS_4CHARS(fourcc));
-+
-+ service = get_listening_service(state, fourcc);
-+
-+ if (service) {
-+ /* A matching service exists */
-+ short version = payload->version;
-+ short version_min = payload->version_min;
-+ if ((service->version < version_min) ||
-+ (version < service->version_min)) {
-+ /* Version mismatch */
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("%d: service %d (%c%c%c%c) "
-+ "version mismatch - local (%d, min %d)"
-+ " vs. remote (%d, min %d)",
-+ state->id, service->localport,
-+ VCHIQ_FOURCC_AS_4CHARS(fourcc),
-+ service->version, service->version_min,
-+ version, version_min);
-+ vchiq_loud_error_footer();
-+ unlock_service(service);
-+ service = NULL;
-+ goto fail_open;
-+ }
-+ service->peer_version = version;
-+
-+ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
-+ struct vchiq_openack_payload ack_payload = {
-+ service->version
-+ };
-+ VCHIQ_ELEMENT_T body = {
-+ &ack_payload,
-+ sizeof(ack_payload)
-+ };
-+
-+ /* Acknowledge the OPEN */
-+ if (service->sync) {
-+ if (queue_message_sync(state, NULL,
-+ VCHIQ_MAKE_MSG(
-+ VCHIQ_MSG_OPENACK,
-+ service->localport,
-+ remoteport),
-+ &body, 1, sizeof(ack_payload),
-+ 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+ } else {
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(
-+ VCHIQ_MSG_OPENACK,
-+ service->localport,
-+ remoteport),
-+ &body, 1, sizeof(ack_payload),
-+ 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+ }
-+
-+ /* The service is now open */
-+ vchiq_set_service_state(service,
-+ service->sync ? VCHIQ_SRVSTATE_OPENSYNC
-+ : VCHIQ_SRVSTATE_OPEN);
-+ }
-+
-+ service->remoteport = remoteport;
-+ service->client_id = ((int *)header->data)[1];
-+ if (make_service_callback(service, VCHIQ_SERVICE_OPENED,
-+ NULL, NULL) == VCHIQ_RETRY) {
-+ /* Bail out if not ready */
-+ service->remoteport = VCHIQ_PORT_FREE;
-+ goto bail_not_ready;
-+ }
-+
-+ /* Success - the message has been dealt with */
-+ unlock_service(service);
-+ return 1;
-+ }
-+ }
-+
-+fail_open:
-+ /* No available service, or an invalid request - send a CLOSE */
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
-+ NULL, 0, 0, 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+
-+ return 1;
-+
-+bail_not_ready:
-+ if (service)
-+ unlock_service(service);
-+
-+ return 0;
-+}
-+
-+/* Called by the slot handler thread */
-+static void
-+parse_rx_slots(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_SHARED_STATE_T *remote = state->remote;
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int tx_pos;
-+ DEBUG_INITIALISE(state->local)
-+
-+ tx_pos = remote->tx_pos;
-+
-+ while (state->rx_pos != tx_pos) {
-+ VCHIQ_HEADER_T *header;
-+ int msgid, size;
-+ int type;
-+ unsigned int localport, remoteport;
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (!state->rx_data) {
-+ int rx_index;
-+ WARN_ON(!((state->rx_pos & VCHIQ_SLOT_MASK) == 0));
-+ rx_index = remote->slot_queue[
-+ SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) &
-+ VCHIQ_SLOT_QUEUE_MASK];
-+ state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state,
-+ rx_index);
-+ state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
-+
-+ /* Initialise use_count to one, and increment
-+ ** release_count at the end of the slot to avoid
-+ ** releasing the slot prematurely. */
-+ state->rx_info->use_count = 1;
-+ state->rx_info->release_count = 0;
-+ }
-+
-+ header = (VCHIQ_HEADER_T *)(state->rx_data +
-+ (state->rx_pos & VCHIQ_SLOT_MASK));
-+ DEBUG_VALUE(PARSE_HEADER, (int)header);
-+ msgid = header->msgid;
-+ DEBUG_VALUE(PARSE_MSGID, msgid);
-+ size = header->size;
-+ type = VCHIQ_MSG_TYPE(msgid);
-+ localport = VCHIQ_MSG_DSTPORT(msgid);
-+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
-+
-+ if (type != VCHIQ_MSG_DATA)
-+ VCHIQ_STATS_INC(state, ctrl_rx_count);
-+
-+ switch (type) {
-+ case VCHIQ_MSG_OPENACK:
-+ case VCHIQ_MSG_CLOSE:
-+ case VCHIQ_MSG_DATA:
-+ case VCHIQ_MSG_BULK_RX:
-+ case VCHIQ_MSG_BULK_TX:
-+ case VCHIQ_MSG_BULK_RX_DONE:
-+ case VCHIQ_MSG_BULK_TX_DONE:
-+ service = find_service_by_port(state, localport);
-+ if ((!service || service->remoteport != remoteport) &&
-+ (localport == 0) &&
-+ (type == VCHIQ_MSG_CLOSE)) {
-+ /* This could be a CLOSE from a client which
-+ hadn't yet received the OPENACK - look for
-+ the connected service */
-+ if (service)
-+ unlock_service(service);
-+ service = get_connected_service(state,
-+ remoteport);
-+ if (service)
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) - "
-+ "found connected service %d",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ service->localport);
-+ }
-+
-+ if (!service) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) - "
-+ "invalid/closed service %d",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport, localport);
-+ goto skip_message;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (vchiq_core_msg_log_level >= VCHIQ_LOG_INFO) {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d "
-+ "len:%d",
-+ msg_type_str(type), type,
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ remoteport, localport, size);
-+ if (size > 0)
-+ vchiq_log_dump_mem("Rcvd", 0, header->data,
-+ min(64, size));
-+ }
-+
-+ if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size)
-+ > VCHIQ_SLOT_SIZE) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "header %x (msgid %x) - size %x too big for "
-+ "slot",
-+ (unsigned int)header, (unsigned int)msgid,
-+ (unsigned int)size);
-+ WARN(1, "oversized for slot\n");
-+ }
-+
-+ switch (type) {
-+ case VCHIQ_MSG_OPEN:
-+ WARN_ON(!(VCHIQ_MSG_DSTPORT(msgid) == 0));
-+ if (!parse_open(state, header))
-+ goto bail_not_ready;
-+ break;
-+ case VCHIQ_MSG_OPENACK:
-+ if (size >= sizeof(struct vchiq_openack_payload)) {
-+ const struct vchiq_openack_payload *payload =
-+ (struct vchiq_openack_payload *)
-+ header->data;
-+ service->peer_version = payload->version;
-+ }
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs OPENACK@%x,%x (%d->%d) v:%d",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport, service->peer_version);
-+ if (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPENING) {
-+ service->remoteport = remoteport;
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_OPEN);
-+ up(&service->remove_event);
-+ } else
-+ vchiq_log_error(vchiq_core_log_level,
-+ "OPENACK received in state %s",
-+ srvstate_names[service->srvstate]);
-+ break;
-+ case VCHIQ_MSG_CLOSE:
-+ WARN_ON(size != 0); /* There should be no data */
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs CLOSE@%x (%d->%d)",
-+ state->id, (unsigned int)header,
-+ remoteport, localport);
-+
-+ mark_service_closing_internal(service, 1);
-+
-+ if (vchiq_close_service_internal(service,
-+ 1/*close_recvd*/) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "Close Service %c%c%c%c s:%u d:%d",
-+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
-+ service->localport,
-+ service->remoteport);
-+ break;
-+ case VCHIQ_MSG_DATA:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs DATA@%x,%x (%d->%d)",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport);
-+
-+ if ((service->remoteport == remoteport)
-+ && (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPEN)) {
-+ header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
-+ claim_slot(state->rx_info);
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (make_service_callback(service,
-+ VCHIQ_MESSAGE_AVAILABLE, header,
-+ NULL) == VCHIQ_RETRY) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ goto bail_not_ready;
-+ }
-+ VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
-+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes,
-+ size);
-+ } else {
-+ VCHIQ_STATS_INC(state, error_count);
-+ }
-+ break;
-+ case VCHIQ_MSG_CONNECT:
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs CONNECT@%x",
-+ state->id, (unsigned int)header);
-+ up(&state->connect);
-+ break;
-+ case VCHIQ_MSG_BULK_RX:
-+ case VCHIQ_MSG_BULK_TX: {
-+ VCHIQ_BULK_QUEUE_T *queue;
-+ WARN_ON(!state->is_master);
-+ queue = (type == VCHIQ_MSG_BULK_RX) ?
-+ &service->bulk_tx : &service->bulk_rx;
-+ if ((service->remoteport == remoteport)
-+ && (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPEN)) {
-+ VCHIQ_BULK_T *bulk;
-+ int resolved = 0;
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (mutex_lock_interruptible(
-+ &service->bulk_mutex) != 0) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ goto bail_not_ready;
-+ }
-+
-+ WARN_ON(!(queue->remote_insert < queue->remove +
-+ VCHIQ_NUM_SERVICE_BULKS));
-+ bulk = &queue->bulks[
-+ BULK_INDEX(queue->remote_insert)];
-+ bulk->remote_data =
-+ (void *)((int *)header->data)[0];
-+ bulk->remote_size = ((int *)header->data)[1];
-+ wmb();
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) %x@%x",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ bulk->remote_size,
-+ (unsigned int)bulk->remote_data);
-+
-+ queue->remote_insert++;
-+
-+ if (atomic_read(&pause_bulks_count)) {
-+ state->deferred_bulks++;
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%s: deferring bulk (%d)",
-+ __func__,
-+ state->deferred_bulks);
-+ if (state->conn_state !=
-+ VCHIQ_CONNSTATE_PAUSE_SENT)
-+ vchiq_log_error(
-+ vchiq_core_log_level,
-+ "%s: bulks paused in "
-+ "unexpected state %s",
-+ __func__,
-+ conn_state_names[
-+ state->conn_state]);
-+ } else if (state->conn_state ==
-+ VCHIQ_CONNSTATE_CONNECTED) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ resolved = resolve_bulks(service,
-+ queue);
-+ }
-+
-+ mutex_unlock(&service->bulk_mutex);
-+ if (resolved)
-+ notify_bulks(service, queue,
-+ 1/*retry_poll*/);
-+ }
-+ } break;
-+ case VCHIQ_MSG_BULK_RX_DONE:
-+ case VCHIQ_MSG_BULK_TX_DONE:
-+ WARN_ON(state->is_master);
-+ if ((service->remoteport == remoteport)
-+ && (service->srvstate !=
-+ VCHIQ_SRVSTATE_FREE)) {
-+ VCHIQ_BULK_QUEUE_T *queue;
-+ VCHIQ_BULK_T *bulk;
-+
-+ queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
-+ &service->bulk_rx : &service->bulk_tx;
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ if (mutex_lock_interruptible(
-+ &service->bulk_mutex) != 0) {
-+ DEBUG_TRACE(PARSE_LINE);
-+ goto bail_not_ready;
-+ }
-+ if ((int)(queue->remote_insert -
-+ queue->local_insert) >= 0) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) "
-+ "unexpected (ri=%d,li=%d)",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ queue->remote_insert,
-+ queue->local_insert);
-+ mutex_unlock(&service->bulk_mutex);
-+ break;
-+ }
-+
-+ BUG_ON(queue->process == queue->local_insert);
-+ BUG_ON(queue->process != queue->remote_insert);
-+
-+ bulk = &queue->bulks[
-+ BULK_INDEX(queue->remote_insert)];
-+ bulk->actual = *(int *)header->data;
-+ queue->remote_insert++;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: prs %s@%x (%d->%d) %x@%x",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport,
-+ bulk->actual, (unsigned int)bulk->data);
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs:%d %cx li=%x ri=%x p=%x",
-+ state->id, localport,
-+ (type == VCHIQ_MSG_BULK_RX_DONE) ?
-+ 'r' : 't',
-+ queue->local_insert,
-+ queue->remote_insert, queue->process);
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ WARN_ON(queue->process == queue->local_insert);
-+ vchiq_complete_bulk(bulk);
-+ queue->process++;
-+ mutex_unlock(&service->bulk_mutex);
-+ DEBUG_TRACE(PARSE_LINE);
-+ notify_bulks(service, queue, 1/*retry_poll*/);
-+ DEBUG_TRACE(PARSE_LINE);
-+ }
-+ break;
-+ case VCHIQ_MSG_PADDING:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs PADDING@%x,%x",
-+ state->id, (unsigned int)header, size);
-+ break;
-+ case VCHIQ_MSG_PAUSE:
-+ /* If initiated, signal the application thread */
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs PAUSE@%x,%x",
-+ state->id, (unsigned int)header, size);
-+ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: PAUSE received in state PAUSED",
-+ state->id);
-+ break;
-+ }
-+ if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
-+ /* Send a PAUSE in response */
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
-+ NULL, 0, 0, 0) == VCHIQ_RETRY)
-+ goto bail_not_ready;
-+ if (state->is_master)
-+ pause_bulks(state);
-+ }
-+ /* At this point slot_mutex is held */
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
-+ vchiq_platform_paused(state);
-+ break;
-+ case VCHIQ_MSG_RESUME:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: prs RESUME@%x,%x",
-+ state->id, (unsigned int)header, size);
-+ /* Release the slot mutex */
-+ mutex_unlock(&state->slot_mutex);
-+ if (state->is_master)
-+ resume_bulks(state);
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
-+ vchiq_platform_resumed(state);
-+ break;
-+
-+ case VCHIQ_MSG_REMOTE_USE:
-+ vchiq_on_remote_use(state);
-+ break;
-+ case VCHIQ_MSG_REMOTE_RELEASE:
-+ vchiq_on_remote_release(state);
-+ break;
-+ case VCHIQ_MSG_REMOTE_USE_ACTIVE:
-+ vchiq_on_remote_use_active(state);
-+ break;
-+
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: prs invalid msgid %x@%x,%x",
-+ state->id, msgid, (unsigned int)header, size);
-+ WARN(1, "invalid message\n");
-+ break;
-+ }
-+
-+skip_message:
-+ if (service) {
-+ unlock_service(service);
-+ service = NULL;
-+ }
-+
-+ state->rx_pos += calc_stride(size);
-+
-+ DEBUG_TRACE(PARSE_LINE);
-+ /* Perform some housekeeping when the end of the slot is
-+ ** reached. */
-+ if ((state->rx_pos & VCHIQ_SLOT_MASK) == 0) {
-+ /* Remove the extra reference count. */
-+ release_slot(state, state->rx_info, NULL, NULL);
-+ state->rx_data = NULL;
-+ }
-+ }
-+
-+bail_not_ready:
-+ if (service)
-+ unlock_service(service);
-+}
-+
-+/* Called by the slot handler thread */
-+static int
-+slot_handler_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ DEBUG_INITIALISE(local)
-+
-+ while (1) {
-+ DEBUG_COUNT(SLOT_HANDLER_COUNT);
-+ DEBUG_TRACE(SLOT_HANDLER_LINE);
-+ remote_event_wait(&local->trigger);
-+
-+ rmb();
-+
-+ DEBUG_TRACE(SLOT_HANDLER_LINE);
-+ if (state->poll_needed) {
-+ /* Check if we need to suspend - may change our
-+ * conn_state */
-+ vchiq_platform_check_suspend(state);
-+
-+ state->poll_needed = 0;
-+
-+ /* Handle service polling and other rare conditions here
-+ ** out of the mainline code */
-+ switch (state->conn_state) {
-+ case VCHIQ_CONNSTATE_CONNECTED:
-+ /* Poll the services as requested */
-+ poll_services(state);
-+ break;
-+
-+ case VCHIQ_CONNSTATE_PAUSING:
-+ if (state->is_master)
-+ pause_bulks(state);
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
-+ NULL, 0, 0, 0) != VCHIQ_RETRY) {
-+ vchiq_set_conn_state(state,
-+ VCHIQ_CONNSTATE_PAUSE_SENT);
-+ } else {
-+ if (state->is_master)
-+ resume_bulks(state);
-+ /* Retry later */
-+ state->poll_needed = 1;
-+ }
-+ break;
-+
-+ case VCHIQ_CONNSTATE_PAUSED:
-+ vchiq_platform_resume(state);
-+ break;
-+
-+ case VCHIQ_CONNSTATE_RESUMING:
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
-+ NULL, 0, 0, 0) != VCHIQ_RETRY) {
-+ if (state->is_master)
-+ resume_bulks(state);
-+ vchiq_set_conn_state(state,
-+ VCHIQ_CONNSTATE_CONNECTED);
-+ vchiq_platform_resumed(state);
-+ } else {
-+ /* This should really be impossible,
-+ ** since the PAUSE should have flushed
-+ ** through outstanding messages. */
-+ vchiq_log_error(vchiq_core_log_level,
-+ "Failed to send RESUME "
-+ "message");
-+ BUG();
-+ }
-+ break;
-+
-+ case VCHIQ_CONNSTATE_PAUSE_TIMEOUT:
-+ case VCHIQ_CONNSTATE_RESUME_TIMEOUT:
-+ vchiq_platform_handle_timeout(state);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+
-+ }
-+
-+ DEBUG_TRACE(SLOT_HANDLER_LINE);
-+ parse_rx_slots(state);
-+ }
-+ return 0;
-+}
-+
-+
-+/* Called by the recycle thread */
-+static int
-+recycle_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+
-+ while (1) {
-+ remote_event_wait(&local->recycle);
-+
-+ process_free_queue(state);
-+ }
-+ return 0;
-+}
-+
-+
-+/* Called by the sync thread */
-+static int
-+sync_func(void *v)
-+{
-+ VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
-+ VCHIQ_SHARED_STATE_T *local = state->local;
-+ VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
-+ state->remote->slot_sync);
-+
-+ while (1) {
-+ VCHIQ_SERVICE_T *service;
-+ int msgid, size;
-+ int type;
-+ unsigned int localport, remoteport;
-+
-+ remote_event_wait(&local->sync_trigger);
-+
-+ rmb();
-+
-+ msgid = header->msgid;
-+ size = header->size;
-+ type = VCHIQ_MSG_TYPE(msgid);
-+ localport = VCHIQ_MSG_DSTPORT(msgid);
-+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
-+
-+ service = find_service_by_port(state, localport);
-+
-+ if (!service) {
-+ vchiq_log_error(vchiq_sync_log_level,
-+ "%d: sf %s@%x (%d->%d) - "
-+ "invalid/closed service %d",
-+ state->id, msg_type_str(type),
-+ (unsigned int)header,
-+ remoteport, localport, localport);
-+ release_message_sync(state, header);
-+ continue;
-+ }
-+
-+ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) {
-+ int svc_fourcc;
-+
-+ svc_fourcc = service
-+ ? service->base.fourcc
-+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
-+ vchiq_log_trace(vchiq_sync_log_level,
-+ "Rcvd Msg %s from %c%c%c%c s:%d d:%d len:%d",
-+ msg_type_str(type),
-+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
-+ remoteport, localport, size);
-+ if (size > 0)
-+ vchiq_log_dump_mem("Rcvd", 0, header->data,
-+ min(64, size));
-+ }
-+
-+ switch (type) {
-+ case VCHIQ_MSG_OPENACK:
-+ if (size >= sizeof(struct vchiq_openack_payload)) {
-+ const struct vchiq_openack_payload *payload =
-+ (struct vchiq_openack_payload *)
-+ header->data;
-+ service->peer_version = payload->version;
-+ }
-+ vchiq_log_info(vchiq_sync_log_level,
-+ "%d: sf OPENACK@%x,%x (%d->%d) v:%d",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport, service->peer_version);
-+ if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
-+ service->remoteport = remoteport;
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_OPENSYNC);
-+ up(&service->remove_event);
-+ }
-+ release_message_sync(state, header);
-+ break;
-+
-+ case VCHIQ_MSG_DATA:
-+ vchiq_log_trace(vchiq_sync_log_level,
-+ "%d: sf DATA@%x,%x (%d->%d)",
-+ state->id, (unsigned int)header, size,
-+ remoteport, localport);
-+
-+ if ((service->remoteport == remoteport) &&
-+ (service->srvstate ==
-+ VCHIQ_SRVSTATE_OPENSYNC)) {
-+ if (make_service_callback(service,
-+ VCHIQ_MESSAGE_AVAILABLE, header,
-+ NULL) == VCHIQ_RETRY)
-+ vchiq_log_error(vchiq_sync_log_level,
-+ "synchronous callback to "
-+ "service %d returns "
-+ "VCHIQ_RETRY",
-+ localport);
-+ }
-+ break;
-+
-+ default:
-+ vchiq_log_error(vchiq_sync_log_level,
-+ "%d: sf unexpected msgid %x@%x,%x",
-+ state->id, msgid, (unsigned int)header, size);
-+ release_message_sync(state, header);
-+ break;
-+ }
-+
-+ unlock_service(service);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static void
-+init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue)
-+{
-+ queue->local_insert = 0;
-+ queue->remote_insert = 0;
-+ queue->process = 0;
-+ queue->remote_notify = 0;
-+ queue->remove = 0;
-+}
-+
-+
-+inline const char *
-+get_conn_state_name(VCHIQ_CONNSTATE_T conn_state)
-+{
-+ return conn_state_names[conn_state];
-+}
-+
-+
-+VCHIQ_SLOT_ZERO_T *
-+vchiq_init_slots(void *mem_base, int mem_size)
-+{
-+ int mem_align = (VCHIQ_SLOT_SIZE - (int)mem_base) & VCHIQ_SLOT_MASK;
-+ VCHIQ_SLOT_ZERO_T *slot_zero =
-+ (VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align);
-+ int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
-+ int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS;
-+
-+ /* Ensure there is enough memory to run an absolutely minimum system */
-+ num_slots -= first_data_slot;
-+
-+ if (num_slots < 4) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_init_slots - insufficient memory %x bytes",
-+ mem_size);
-+ return NULL;
-+ }
-+
-+ memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T));
-+
-+ slot_zero->magic = VCHIQ_MAGIC;
-+ slot_zero->version = VCHIQ_VERSION;
-+ slot_zero->version_min = VCHIQ_VERSION_MIN;
-+ slot_zero->slot_zero_size = sizeof(VCHIQ_SLOT_ZERO_T);
-+ slot_zero->slot_size = VCHIQ_SLOT_SIZE;
-+ slot_zero->max_slots = VCHIQ_MAX_SLOTS;
-+ slot_zero->max_slots_per_side = VCHIQ_MAX_SLOTS_PER_SIDE;
-+
-+ slot_zero->master.slot_sync = first_data_slot;
-+ slot_zero->master.slot_first = first_data_slot + 1;
-+ slot_zero->master.slot_last = first_data_slot + (num_slots/2) - 1;
-+ slot_zero->slave.slot_sync = first_data_slot + (num_slots/2);
-+ slot_zero->slave.slot_first = first_data_slot + (num_slots/2) + 1;
-+ slot_zero->slave.slot_last = first_data_slot + num_slots - 1;
-+
-+ return slot_zero;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
-+ int is_master)
-+{
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_SHARED_STATE_T *remote;
-+ VCHIQ_STATUS_T status;
-+ char threadname[10];
-+ static int id;
-+ int i;
-+
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%s: slot_zero = 0x%08lx, is_master = %d",
-+ __func__, (unsigned long)slot_zero, is_master);
-+
-+ /* Check the input configuration */
-+
-+ if (slot_zero->magic != VCHIQ_MAGIC) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("Invalid VCHIQ magic value found.");
-+ vchiq_loud_error("slot_zero=%x: magic=%x (expected %x)",
-+ (unsigned int)slot_zero, slot_zero->magic, VCHIQ_MAGIC);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if (slot_zero->version < VCHIQ_VERSION_MIN) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("Incompatible VCHIQ versions found.");
-+ vchiq_loud_error("slot_zero=%x: VideoCore version=%d "
-+ "(minimum %d)",
-+ (unsigned int)slot_zero, slot_zero->version,
-+ VCHIQ_VERSION_MIN);
-+ vchiq_loud_error("Restart with a newer VideoCore image.");
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if (VCHIQ_VERSION < slot_zero->version_min) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("Incompatible VCHIQ versions found.");
-+ vchiq_loud_error("slot_zero=%x: version=%d (VideoCore "
-+ "minimum %d)",
-+ (unsigned int)slot_zero, VCHIQ_VERSION,
-+ slot_zero->version_min);
-+ vchiq_loud_error("Restart with a newer kernel.");
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if ((slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T)) ||
-+ (slot_zero->slot_size != VCHIQ_SLOT_SIZE) ||
-+ (slot_zero->max_slots != VCHIQ_MAX_SLOTS) ||
-+ (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)) {
-+ vchiq_loud_error_header();
-+ if (slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T))
-+ vchiq_loud_error("slot_zero=%x: slot_zero_size=%x "
-+ "(expected %x)",
-+ (unsigned int)slot_zero,
-+ slot_zero->slot_zero_size,
-+ sizeof(VCHIQ_SLOT_ZERO_T));
-+ if (slot_zero->slot_size != VCHIQ_SLOT_SIZE)
-+ vchiq_loud_error("slot_zero=%x: slot_size=%d "
-+ "(expected %d",
-+ (unsigned int)slot_zero, slot_zero->slot_size,
-+ VCHIQ_SLOT_SIZE);
-+ if (slot_zero->max_slots != VCHIQ_MAX_SLOTS)
-+ vchiq_loud_error("slot_zero=%x: max_slots=%d "
-+ "(expected %d)",
-+ (unsigned int)slot_zero, slot_zero->max_slots,
-+ VCHIQ_MAX_SLOTS);
-+ if (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)
-+ vchiq_loud_error("slot_zero=%x: max_slots_per_side=%d "
-+ "(expected %d)",
-+ (unsigned int)slot_zero,
-+ slot_zero->max_slots_per_side,
-+ VCHIQ_MAX_SLOTS_PER_SIDE);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ if (is_master) {
-+ local = &slot_zero->master;
-+ remote = &slot_zero->slave;
-+ } else {
-+ local = &slot_zero->slave;
-+ remote = &slot_zero->master;
-+ }
-+
-+ if (local->initialised) {
-+ vchiq_loud_error_header();
-+ if (remote->initialised)
-+ vchiq_loud_error("local state has already been "
-+ "initialised");
-+ else
-+ vchiq_loud_error("master/slave mismatch - two %ss",
-+ is_master ? "master" : "slave");
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+
-+ memset(state, 0, sizeof(VCHIQ_STATE_T));
-+
-+ state->id = id++;
-+ state->is_master = is_master;
-+
-+ /*
-+ initialize shared state pointers
-+ */
-+
-+ state->local = local;
-+ state->remote = remote;
-+ state->slot_data = (VCHIQ_SLOT_T *)slot_zero;
-+
-+ /*
-+ initialize events and mutexes
-+ */
-+
-+ sema_init(&state->connect, 0);
-+ mutex_init(&state->mutex);
-+ sema_init(&state->trigger_event, 0);
-+ sema_init(&state->recycle_event, 0);
-+ sema_init(&state->sync_trigger_event, 0);
-+ sema_init(&state->sync_release_event, 0);
-+
-+ mutex_init(&state->slot_mutex);
-+ mutex_init(&state->recycle_mutex);
-+ mutex_init(&state->sync_mutex);
-+ mutex_init(&state->bulk_transfer_mutex);
-+
-+ sema_init(&state->slot_available_event, 0);
-+ sema_init(&state->slot_remove_event, 0);
-+ sema_init(&state->data_quota_event, 0);
-+
-+ state->slot_queue_available = 0;
-+
-+ for (i = 0; i < VCHIQ_MAX_SERVICES; i++) {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &state->service_quotas[i];
-+ sema_init(&service_quota->quota_event, 0);
-+ }
-+
-+ for (i = local->slot_first; i <= local->slot_last; i++) {
-+ local->slot_queue[state->slot_queue_available++] = i;
-+ up(&state->slot_available_event);
-+ }
-+
-+ state->default_slot_quota = state->slot_queue_available/2;
-+ state->default_message_quota =
-+ min((unsigned short)(state->default_slot_quota * 256),
-+ (unsigned short)~0);
-+
-+ state->previous_data_index = -1;
-+ state->data_use_count = 0;
-+ state->data_quota = state->slot_queue_available - 1;
-+
-+ local->trigger.event = &state->trigger_event;
-+ remote_event_create(&local->trigger);
-+ local->tx_pos = 0;
-+
-+ local->recycle.event = &state->recycle_event;
-+ remote_event_create(&local->recycle);
-+ local->slot_queue_recycle = state->slot_queue_available;
-+
-+ local->sync_trigger.event = &state->sync_trigger_event;
-+ remote_event_create(&local->sync_trigger);
-+
-+ local->sync_release.event = &state->sync_release_event;
-+ remote_event_create(&local->sync_release);
-+
-+ /* At start-of-day, the slot is empty and available */
-+ ((VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, local->slot_sync))->msgid
-+ = VCHIQ_MSGID_PADDING;
-+ remote_event_signal_local(&local->sync_release);
-+
-+ local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
-+
-+ status = vchiq_platform_init_state(state);
-+
-+ /*
-+ bring up slot handler thread
-+ */
-+ snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id);
-+ state->slot_handler_thread = kthread_create(&slot_handler_func,
-+ (void *)state,
-+ threadname);
-+
-+ if (state->slot_handler_thread == NULL) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("couldn't create thread %s", threadname);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+ set_user_nice(state->slot_handler_thread, -19);
-+ wake_up_process(state->slot_handler_thread);
-+
-+ snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id);
-+ state->recycle_thread = kthread_create(&recycle_func,
-+ (void *)state,
-+ threadname);
-+ if (state->recycle_thread == NULL) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("couldn't create thread %s", threadname);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+ set_user_nice(state->recycle_thread, -19);
-+ wake_up_process(state->recycle_thread);
-+
-+ snprintf(threadname, sizeof(threadname), "VCHIQs-%d", state->id);
-+ state->sync_thread = kthread_create(&sync_func,
-+ (void *)state,
-+ threadname);
-+ if (state->sync_thread == NULL) {
-+ vchiq_loud_error_header();
-+ vchiq_loud_error("couldn't create thread %s", threadname);
-+ vchiq_loud_error_footer();
-+ return VCHIQ_ERROR;
-+ }
-+ set_user_nice(state->sync_thread, -20);
-+ wake_up_process(state->sync_thread);
-+
-+ BUG_ON(state->id >= VCHIQ_MAX_STATES);
-+ vchiq_states[state->id] = state;
-+
-+ /* Indicate readiness to the other side */
-+ local->initialised = 1;
-+
-+ return status;
-+}
-+
-+/* Called from application thread when a client or server service is created. */
-+VCHIQ_SERVICE_T *
-+vchiq_add_service_internal(VCHIQ_STATE_T *state,
-+ const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
-+ VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term)
-+{
-+ VCHIQ_SERVICE_T *service;
-+
-+ service = kmalloc(sizeof(VCHIQ_SERVICE_T), GFP_KERNEL);
-+ if (service) {
-+ service->base.fourcc = params->fourcc;
-+ service->base.callback = params->callback;
-+ service->base.userdata = params->userdata;
-+ service->handle = VCHIQ_SERVICE_HANDLE_INVALID;
-+ service->ref_count = 1;
-+ service->srvstate = VCHIQ_SRVSTATE_FREE;
-+ service->userdata_term = userdata_term;
-+ service->localport = VCHIQ_PORT_FREE;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+
-+ service->public_fourcc = (srvstate == VCHIQ_SRVSTATE_OPENING) ?
-+ VCHIQ_FOURCC_INVALID : params->fourcc;
-+ service->client_id = 0;
-+ service->auto_close = 1;
-+ service->sync = 0;
-+ service->closing = 0;
-+ atomic_set(&service->poll_flags, 0);
-+ service->version = params->version;
-+ service->version_min = params->version_min;
-+ service->state = state;
-+ service->instance = instance;
-+ service->service_use_count = 0;
-+ init_bulk_queue(&service->bulk_tx);
-+ init_bulk_queue(&service->bulk_rx);
-+ sema_init(&service->remove_event, 0);
-+ sema_init(&service->bulk_remove_event, 0);
-+ mutex_init(&service->bulk_mutex);
-+ memset(&service->stats, 0, sizeof(service->stats));
-+ } else {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "Out of memory");
-+ }
-+
-+ if (service) {
-+ VCHIQ_SERVICE_T **pservice = NULL;
-+ int i;
-+
-+ /* Although it is perfectly possible to use service_spinlock
-+ ** to protect the creation of services, it is overkill as it
-+ ** disables interrupts while the array is searched.
-+ ** The only danger is of another thread trying to create a
-+ ** service - service deletion is safe.
-+ ** Therefore it is preferable to use state->mutex which,
-+ ** although slower to claim, doesn't block interrupts while
-+ ** it is held.
-+ */
-+
-+ mutex_lock(&state->mutex);
-+
-+ /* Prepare to use a previously unused service */
-+ if (state->unused_service < VCHIQ_MAX_SERVICES)
-+ pservice = &state->services[state->unused_service];
-+
-+ if (srvstate == VCHIQ_SRVSTATE_OPENING) {
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *srv = state->services[i];
-+ if (!srv) {
-+ pservice = &state->services[i];
-+ break;
-+ }
-+ }
-+ } else {
-+ for (i = (state->unused_service - 1); i >= 0; i--) {
-+ VCHIQ_SERVICE_T *srv = state->services[i];
-+ if (!srv)
-+ pservice = &state->services[i];
-+ else if ((srv->public_fourcc == params->fourcc)
-+ && ((srv->instance != instance) ||
-+ (srv->base.callback !=
-+ params->callback))) {
-+ /* There is another server using this
-+ ** fourcc which doesn't match. */
-+ pservice = NULL;
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (pservice) {
-+ service->localport = (pservice - state->services);
-+ if (!handle_seq)
-+ handle_seq = VCHIQ_MAX_STATES *
-+ VCHIQ_MAX_SERVICES;
-+ service->handle = handle_seq |
-+ (state->id * VCHIQ_MAX_SERVICES) |
-+ service->localport;
-+ handle_seq += VCHIQ_MAX_STATES * VCHIQ_MAX_SERVICES;
-+ *pservice = service;
-+ if (pservice == &state->services[state->unused_service])
-+ state->unused_service++;
-+ }
-+
-+ mutex_unlock(&state->mutex);
-+
-+ if (!pservice) {
-+ kfree(service);
-+ service = NULL;
-+ }
-+ }
-+
-+ if (service) {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &state->service_quotas[service->localport];
-+ service_quota->slot_quota = state->default_slot_quota;
-+ service_quota->message_quota = state->default_message_quota;
-+ if (service_quota->slot_use_count == 0)
-+ service_quota->previous_tx_index =
-+ SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos)
-+ - 1;
-+
-+ /* Bring this service online */
-+ vchiq_set_service_state(service, srvstate);
-+
-+ vchiq_log_info(vchiq_core_msg_log_level,
-+ "%s Service %c%c%c%c SrcPort:%d",
-+ (srvstate == VCHIQ_SRVSTATE_OPENING)
-+ ? "Open" : "Add",
-+ VCHIQ_FOURCC_AS_4CHARS(params->fourcc),
-+ service->localport);
-+ }
-+
-+ /* Don't unlock the service - leave it with a ref_count of 1. */
-+
-+ return service;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id)
-+{
-+ struct vchiq_open_payload payload = {
-+ service->base.fourcc,
-+ client_id,
-+ service->version,
-+ service->version_min
-+ };
-+ VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) };
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ service->client_id = client_id;
-+ vchiq_use_service_internal(service);
-+ status = queue_message(service->state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0),
-+ &body, 1, sizeof(payload), 1);
-+ if (status == VCHIQ_SUCCESS) {
-+ if (down_interruptible(&service->remove_event) != 0) {
-+ status = VCHIQ_RETRY;
-+ vchiq_release_service_internal(service);
-+ } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
-+ if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: osi - srvstate = %s (ref %d)",
-+ service->state->id,
-+ srvstate_names[service->srvstate],
-+ service->ref_count);
-+ status = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_STATS_INC(service, error_count);
-+ vchiq_release_service_internal(service);
-+ }
-+ }
-+ return status;
-+}
-+
-+static void
-+release_service_messages(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ int slot_last = state->remote->slot_last;
-+ int i;
-+
-+ /* Release any claimed messages */
-+ for (i = state->remote->slot_first; i <= slot_last; i++) {
-+ VCHIQ_SLOT_INFO_T *slot_info =
-+ SLOT_INFO_FROM_INDEX(state, i);
-+ if (slot_info->release_count != slot_info->use_count) {
-+ char *data =
-+ (char *)SLOT_DATA_FROM_INDEX(state, i);
-+ unsigned int pos, end;
-+
-+ end = VCHIQ_SLOT_SIZE;
-+ if (data == state->rx_data)
-+ /* This buffer is still being read from - stop
-+ ** at the current read position */
-+ end = state->rx_pos & VCHIQ_SLOT_MASK;
-+
-+ pos = 0;
-+
-+ while (pos < end) {
-+ VCHIQ_HEADER_T *header =
-+ (VCHIQ_HEADER_T *)(data + pos);
-+ int msgid = header->msgid;
-+ int port = VCHIQ_MSG_DSTPORT(msgid);
-+ if ((port == service->localport) &&
-+ (msgid & VCHIQ_MSGID_CLAIMED)) {
-+ vchiq_log_info(vchiq_core_log_level,
-+ " fsi - hdr %x",
-+ (unsigned int)header);
-+ release_slot(state, slot_info, header,
-+ NULL);
-+ }
-+ pos += calc_stride(header->size);
-+ if (pos > VCHIQ_SLOT_SIZE) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "fsi - pos %x: header %x, "
-+ "msgid %x, header->msgid %x, "
-+ "header->size %x",
-+ pos, (unsigned int)header,
-+ msgid, header->msgid,
-+ header->size);
-+ WARN(1, "invalid slot position\n");
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+static int
-+do_abort_bulks(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATUS_T status;
-+
-+ /* Abort any outstanding bulk transfers */
-+ if (mutex_lock_interruptible(&service->bulk_mutex) != 0)
-+ return 0;
-+ abort_outstanding_bulks(service, &service->bulk_tx);
-+ abort_outstanding_bulks(service, &service->bulk_rx);
-+ mutex_unlock(&service->bulk_mutex);
-+
-+ status = notify_bulks(service, &service->bulk_tx, 0/*!retry_poll*/);
-+ if (status == VCHIQ_SUCCESS)
-+ status = notify_bulks(service, &service->bulk_rx,
-+ 0/*!retry_poll*/);
-+ return (status == VCHIQ_SUCCESS);
-+}
-+
-+static VCHIQ_STATUS_T
-+close_service_complete(VCHIQ_SERVICE_T *service, int failstate)
-+{
-+ VCHIQ_STATUS_T status;
-+ int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
-+ int newstate;
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_OPEN:
-+ case VCHIQ_SRVSTATE_CLOSESENT:
-+ case VCHIQ_SRVSTATE_CLOSERECVD:
-+ if (is_server) {
-+ if (service->auto_close) {
-+ service->client_id = 0;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+ newstate = VCHIQ_SRVSTATE_LISTENING;
-+ } else
-+ newstate = VCHIQ_SRVSTATE_CLOSEWAIT;
-+ } else
-+ newstate = VCHIQ_SRVSTATE_CLOSED;
-+ vchiq_set_service_state(service, newstate);
-+ break;
-+ case VCHIQ_SRVSTATE_LISTENING:
-+ break;
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "close_service_complete(%x) called in state %s",
-+ service->handle, srvstate_names[service->srvstate]);
-+ WARN(1, "close_service_complete in unexpected state\n");
-+ return VCHIQ_ERROR;
-+ }
-+
-+ status = make_service_callback(service,
-+ VCHIQ_SERVICE_CLOSED, NULL, NULL);
-+
-+ if (status != VCHIQ_RETRY) {
-+ int uc = service->service_use_count;
-+ int i;
-+ /* Complete the close process */
-+ for (i = 0; i < uc; i++)
-+ /* cater for cases where close is forced and the
-+ ** client may not close all it's handles */
-+ vchiq_release_service_internal(service);
-+
-+ service->client_id = 0;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+
-+ if (service->srvstate == VCHIQ_SRVSTATE_CLOSED)
-+ vchiq_free_service_internal(service);
-+ else if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) {
-+ if (is_server)
-+ service->closing = 0;
-+
-+ up(&service->remove_event);
-+ }
-+ } else
-+ vchiq_set_service_state(service, failstate);
-+
-+ return status;
-+}
-+
-+/* Called by the slot handler */
-+VCHIQ_STATUS_T
-+vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+ int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
-+
-+ vchiq_log_info(vchiq_core_log_level, "%d: csi:%d,%d (%s)",
-+ service->state->id, service->localport, close_recvd,
-+ srvstate_names[service->srvstate]);
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_CLOSED:
-+ case VCHIQ_SRVSTATE_HIDDEN:
-+ case VCHIQ_SRVSTATE_LISTENING:
-+ case VCHIQ_SRVSTATE_CLOSEWAIT:
-+ if (close_recvd)
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_close_service_internal(1) called "
-+ "in state %s",
-+ srvstate_names[service->srvstate]);
-+ else if (is_server) {
-+ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
-+ status = VCHIQ_ERROR;
-+ } else {
-+ service->client_id = 0;
-+ service->remoteport = VCHIQ_PORT_FREE;
-+ if (service->srvstate ==
-+ VCHIQ_SRVSTATE_CLOSEWAIT)
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_LISTENING);
-+ }
-+ up(&service->remove_event);
-+ } else
-+ vchiq_free_service_internal(service);
-+ break;
-+ case VCHIQ_SRVSTATE_OPENING:
-+ if (close_recvd) {
-+ /* The open was rejected - tell the user */
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_CLOSEWAIT);
-+ up(&service->remove_event);
-+ } else {
-+ /* Shutdown mid-open - let the other side know */
-+ status = queue_message(state, service,
-+ VCHIQ_MAKE_MSG
-+ (VCHIQ_MSG_CLOSE,
-+ service->localport,
-+ VCHIQ_MSG_DSTPORT(service->remoteport)),
-+ NULL, 0, 0, 0);
-+ }
-+ break;
-+
-+ case VCHIQ_SRVSTATE_OPENSYNC:
-+ mutex_lock(&state->sync_mutex);
-+ /* Drop through */
-+
-+ case VCHIQ_SRVSTATE_OPEN:
-+ if (state->is_master || close_recvd) {
-+ if (!do_abort_bulks(service))
-+ status = VCHIQ_RETRY;
-+ }
-+
-+ release_service_messages(service);
-+
-+ if (status == VCHIQ_SUCCESS)
-+ status = queue_message(state, service,
-+ VCHIQ_MAKE_MSG
-+ (VCHIQ_MSG_CLOSE,
-+ service->localport,
-+ VCHIQ_MSG_DSTPORT(service->remoteport)),
-+ NULL, 0, 0, 0);
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ if (!close_recvd)
-+ break;
-+ } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) {
-+ mutex_unlock(&state->sync_mutex);
-+ break;
-+ } else
-+ break;
-+
-+ status = close_service_complete(service,
-+ VCHIQ_SRVSTATE_CLOSERECVD);
-+ break;
-+
-+ case VCHIQ_SRVSTATE_CLOSESENT:
-+ if (!close_recvd)
-+ /* This happens when a process is killed mid-close */
-+ break;
-+
-+ if (!state->is_master) {
-+ if (!do_abort_bulks(service)) {
-+ status = VCHIQ_RETRY;
-+ break;
-+ }
-+ }
-+
-+ if (status == VCHIQ_SUCCESS)
-+ status = close_service_complete(service,
-+ VCHIQ_SRVSTATE_CLOSERECVD);
-+ break;
-+
-+ case VCHIQ_SRVSTATE_CLOSERECVD:
-+ if (!close_recvd && is_server)
-+ /* Force into LISTENING mode */
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_LISTENING);
-+ status = close_service_complete(service,
-+ VCHIQ_SRVSTATE_CLOSERECVD);
-+ break;
-+
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_close_service_internal(%d) called in state %s",
-+ close_recvd, srvstate_names[service->srvstate]);
-+ break;
-+ }
-+
-+ return status;
-+}
-+
-+/* Called from the application process upon process death */
-+void
-+vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+
-+ vchiq_log_info(vchiq_core_log_level, "%d: tsi - (%d<->%d)",
-+ state->id, service->localport, service->remoteport);
-+
-+ mark_service_closing(service);
-+
-+ /* Mark the service for removal by the slot handler */
-+ request_poll(state, service, VCHIQ_POLL_REMOVE);
-+}
-+
-+/* Called from the slot handler */
-+void
-+vchiq_free_service_internal(VCHIQ_SERVICE_T *service)
-+{
-+ VCHIQ_STATE_T *state = service->state;
-+
-+ vchiq_log_info(vchiq_core_log_level, "%d: fsi - (%d)",
-+ state->id, service->localport);
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_OPENING:
-+ case VCHIQ_SRVSTATE_CLOSED:
-+ case VCHIQ_SRVSTATE_HIDDEN:
-+ case VCHIQ_SRVSTATE_LISTENING:
-+ case VCHIQ_SRVSTATE_CLOSEWAIT:
-+ break;
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%d: fsi - (%d) in state %s",
-+ state->id, service->localport,
-+ srvstate_names[service->srvstate]);
-+ return;
-+ }
-+
-+ vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
-+
-+ up(&service->remove_event);
-+
-+ /* Release the initial lock */
-+ unlock_service(service);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+
-+ /* Find all services registered to this client and enable them. */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance,
-+ &i)) != NULL) {
-+ if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
-+ vchiq_set_service_state(service,
-+ VCHIQ_SRVSTATE_LISTENING);
-+ unlock_service(service);
-+ }
-+
-+ if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
-+ if (queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
-+ 0, 1) == VCHIQ_RETRY)
-+ return VCHIQ_RETRY;
-+
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING);
-+ }
-+
-+ if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
-+ if (down_interruptible(&state->connect) != 0)
-+ return VCHIQ_RETRY;
-+
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
-+ up(&state->connect);
-+ }
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_SERVICE_T *service;
-+ int i;
-+
-+ /* Find all services registered to this client and enable them. */
-+ i = 0;
-+ while ((service = next_service_by_instance(state, instance,
-+ &i)) != NULL) {
-+ (void)vchiq_remove_service(service->handle);
-+ unlock_service(service);
-+ }
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_pause_internal(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ switch (state->conn_state) {
-+ case VCHIQ_CONNSTATE_CONNECTED:
-+ /* Request a pause */
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
-+ request_poll(state, NULL, 0);
-+ break;
-+ default:
-+ vchiq_log_error(vchiq_core_log_level,
-+ "vchiq_pause_internal in state %s\n",
-+ conn_state_names[state->conn_state]);
-+ status = VCHIQ_ERROR;
-+ VCHIQ_STATS_INC(state, error_count);
-+ break;
-+ }
-+
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_resume_internal(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
-+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
-+ request_poll(state, NULL, 0);
-+ } else {
-+ status = VCHIQ_ERROR;
-+ VCHIQ_STATS_INC(state, error_count);
-+ }
-+
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ /* Unregister the service */
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (!service)
-+ return VCHIQ_ERROR;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: close_service:%d",
-+ service->state->id, service->localport);
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) {
-+ unlock_service(service);
-+ return VCHIQ_ERROR;
-+ }
-+
-+ mark_service_closing(service);
-+
-+ if (current == service->state->slot_handler_thread) {
-+ status = vchiq_close_service_internal(service,
-+ 0/*!close_recvd*/);
-+ BUG_ON(status == VCHIQ_RETRY);
-+ } else {
-+ /* Mark the service for termination by the slot handler */
-+ request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
-+ }
-+
-+ while (1) {
-+ if (down_interruptible(&service->remove_event) != 0) {
-+ status = VCHIQ_RETRY;
-+ break;
-+ }
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_OPEN))
-+ break;
-+
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: close_service:%d - waiting in state %s",
-+ service->state->id, service->localport,
-+ srvstate_names[service->srvstate]);
-+ }
-+
-+ if ((status == VCHIQ_SUCCESS) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_LISTENING))
-+ status = VCHIQ_ERROR;
-+
-+ unlock_service(service);
-+
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ /* Unregister the service */
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-+
-+ if (!service)
-+ return VCHIQ_ERROR;
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: remove_service:%d",
-+ service->state->id, service->localport);
-+
-+ if (service->srvstate == VCHIQ_SRVSTATE_FREE) {
-+ unlock_service(service);
-+ return VCHIQ_ERROR;
-+ }
-+
-+ mark_service_closing(service);
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
-+ (current == service->state->slot_handler_thread)) {
-+ /* Make it look like a client, because it must be removed and
-+ not left in the LISTENING state. */
-+ service->public_fourcc = VCHIQ_FOURCC_INVALID;
-+
-+ status = vchiq_close_service_internal(service,
-+ 0/*!close_recvd*/);
-+ BUG_ON(status == VCHIQ_RETRY);
-+ } else {
-+ /* Mark the service for removal by the slot handler */
-+ request_poll(service->state, service, VCHIQ_POLL_REMOVE);
-+ }
-+ while (1) {
-+ if (down_interruptible(&service->remove_event) != 0) {
-+ status = VCHIQ_RETRY;
-+ break;
-+ }
-+
-+ if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-+ (service->srvstate == VCHIQ_SRVSTATE_OPEN))
-+ break;
-+
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%d: remove_service:%d - waiting in state %s",
-+ service->state->id, service->localport,
-+ srvstate_names[service->srvstate]);
-+ }
-+
-+ if ((status == VCHIQ_SUCCESS) &&
-+ (service->srvstate != VCHIQ_SRVSTATE_FREE))
-+ status = VCHIQ_ERROR;
-+
-+ unlock_service(service);
-+
-+ return status;
-+}
-+
-+
-+/* This function may be called by kernel threads or user threads.
-+ * User threads may receive VCHIQ_RETRY to indicate that a signal has been
-+ * received and the call should be retried after being returned to user
-+ * context.
-+ * When called in blocking mode, the userdata field points to a bulk_waiter
-+ * structure.
-+ */
-+VCHIQ_STATUS_T
-+vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_BULK_QUEUE_T *queue;
-+ VCHIQ_BULK_T *bulk;
-+ VCHIQ_STATE_T *state;
-+ struct bulk_waiter *bulk_waiter = NULL;
-+ const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r';
-+ const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ?
-+ VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX;
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+
-+ if (!service ||
-+ (service->srvstate != VCHIQ_SRVSTATE_OPEN) ||
-+ ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)) ||
-+ (vchiq_check_service(service) != VCHIQ_SUCCESS))
-+ goto error_exit;
-+
-+ switch (mode) {
-+ case VCHIQ_BULK_MODE_NOCALLBACK:
-+ case VCHIQ_BULK_MODE_CALLBACK:
-+ break;
-+ case VCHIQ_BULK_MODE_BLOCKING:
-+ bulk_waiter = (struct bulk_waiter *)userdata;
-+ sema_init(&bulk_waiter->event, 0);
-+ bulk_waiter->actual = 0;
-+ bulk_waiter->bulk = NULL;
-+ break;
-+ case VCHIQ_BULK_MODE_WAITING:
-+ bulk_waiter = (struct bulk_waiter *)userdata;
-+ bulk = bulk_waiter->bulk;
-+ goto waiting;
-+ default:
-+ goto error_exit;
-+ }
-+
-+ state = service->state;
-+
-+ queue = (dir == VCHIQ_BULK_TRANSMIT) ?
-+ &service->bulk_tx : &service->bulk_rx;
-+
-+ if (mutex_lock_interruptible(&service->bulk_mutex) != 0) {
-+ status = VCHIQ_RETRY;
-+ goto error_exit;
-+ }
-+
-+ if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS) {
-+ VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
-+ do {
-+ mutex_unlock(&service->bulk_mutex);
-+ if (down_interruptible(&service->bulk_remove_event)
-+ != 0) {
-+ status = VCHIQ_RETRY;
-+ goto error_exit;
-+ }
-+ if (mutex_lock_interruptible(&service->bulk_mutex)
-+ != 0) {
-+ status = VCHIQ_RETRY;
-+ goto error_exit;
-+ }
-+ } while (queue->local_insert == queue->remove +
-+ VCHIQ_NUM_SERVICE_BULKS);
-+ }
-+
-+ bulk = &queue->bulks[BULK_INDEX(queue->local_insert)];
-+
-+ bulk->mode = mode;
-+ bulk->dir = dir;
-+ bulk->userdata = userdata;
-+ bulk->size = size;
-+ bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
-+
-+ if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) !=
-+ VCHIQ_SUCCESS)
-+ goto unlock_error_exit;
-+
-+ wmb();
-+
-+ vchiq_log_info(vchiq_core_log_level,
-+ "%d: bt (%d->%d) %cx %x@%x %x",
-+ state->id,
-+ service->localport, service->remoteport, dir_char,
-+ size, (unsigned int)bulk->data, (unsigned int)userdata);
-+
-+ if (state->is_master) {
-+ queue->local_insert++;
-+ if (resolve_bulks(service, queue))
-+ request_poll(state, service,
-+ (dir == VCHIQ_BULK_TRANSMIT) ?
-+ VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
-+ } else {
-+ int payload[2] = { (int)bulk->data, bulk->size };
-+ VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
-+
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(dir_msgtype,
-+ service->localport, service->remoteport),
-+ &element, 1, sizeof(payload), 1);
-+ if (status != VCHIQ_SUCCESS) {
-+ vchiq_complete_bulk(bulk);
-+ goto unlock_error_exit;
-+ }
-+ queue->local_insert++;
-+ }
-+
-+ mutex_unlock(&service->bulk_mutex);
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%d: bt:%d %cx li=%x ri=%x p=%x",
-+ state->id,
-+ service->localport, dir_char,
-+ queue->local_insert, queue->remote_insert, queue->process);
-+
-+waiting:
-+ unlock_service(service);
-+
-+ status = VCHIQ_SUCCESS;
-+
-+ if (bulk_waiter) {
-+ bulk_waiter->bulk = bulk;
-+ if (down_interruptible(&bulk_waiter->event) != 0)
-+ status = VCHIQ_RETRY;
-+ else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
-+ status = VCHIQ_ERROR;
-+ }
-+
-+ return status;
-+
-+unlock_error_exit:
-+ mutex_unlock(&service->bulk_mutex);
-+
-+error_exit:
-+ if (service)
-+ unlock_service(service);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
-+ const VCHIQ_ELEMENT_T *elements, unsigned int count)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+
-+ unsigned int size = 0;
-+ unsigned int i;
-+
-+ if (!service ||
-+ (vchiq_check_service(service) != VCHIQ_SUCCESS))
-+ goto error_exit;
-+
-+ for (i = 0; i < (unsigned int)count; i++) {
-+ if (elements[i].size) {
-+ if (elements[i].data == NULL) {
-+ VCHIQ_SERVICE_STATS_INC(service, error_count);
-+ goto error_exit;
-+ }
-+ size += elements[i].size;
-+ }
-+ }
-+
-+ if (size > VCHIQ_MAX_MSG_SIZE) {
-+ VCHIQ_SERVICE_STATS_INC(service, error_count);
-+ goto error_exit;
-+ }
-+
-+ switch (service->srvstate) {
-+ case VCHIQ_SRVSTATE_OPEN:
-+ status = queue_message(service->state, service,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
-+ service->localport,
-+ service->remoteport),
-+ elements, count, size, 1);
-+ break;
-+ case VCHIQ_SRVSTATE_OPENSYNC:
-+ status = queue_message_sync(service->state, service,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
-+ service->localport,
-+ service->remoteport),
-+ elements, count, size, 1);
-+ break;
-+ default:
-+ status = VCHIQ_ERROR;
-+ break;
-+ }
-+
-+error_exit:
-+ if (service)
-+ unlock_service(service);
-+
-+ return status;
-+}
-+
-+void
-+vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_SHARED_STATE_T *remote;
-+ VCHIQ_STATE_T *state;
-+ int slot_index;
-+
-+ if (!service)
-+ return;
-+
-+ state = service->state;
-+ remote = state->remote;
-+
-+ slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header);
-+
-+ if ((slot_index >= remote->slot_first) &&
-+ (slot_index <= remote->slot_last)) {
-+ int msgid = header->msgid;
-+ if (msgid & VCHIQ_MSGID_CLAIMED) {
-+ VCHIQ_SLOT_INFO_T *slot_info =
-+ SLOT_INFO_FROM_INDEX(state, slot_index);
-+
-+ release_slot(state, slot_info, header, service);
-+ }
-+ } else if (slot_index == remote->slot_sync)
-+ release_message_sync(state, header);
-+
-+ unlock_service(service);
-+}
-+
-+static void
-+release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
-+{
-+ header->msgid = VCHIQ_MSGID_PADDING;
-+ wmb();
-+ remote_event_signal(&state->remote->sync_release);
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+
-+ if (!service ||
-+ (vchiq_check_service(service) != VCHIQ_SUCCESS) ||
-+ !peer_version)
-+ goto exit;
-+ *peer_version = service->peer_version;
-+ status = VCHIQ_SUCCESS;
-+
-+exit:
-+ if (service)
-+ unlock_service(service);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_get_config(VCHIQ_INSTANCE_T instance,
-+ int config_size, VCHIQ_CONFIG_T *pconfig)
-+{
-+ VCHIQ_CONFIG_T config;
-+
-+ (void)instance;
-+
-+ config.max_msg_size = VCHIQ_MAX_MSG_SIZE;
-+ config.bulk_threshold = VCHIQ_MAX_MSG_SIZE;
-+ config.max_outstanding_bulks = VCHIQ_NUM_SERVICE_BULKS;
-+ config.max_services = VCHIQ_MAX_SERVICES;
-+ config.version = VCHIQ_VERSION;
-+ config.version_min = VCHIQ_VERSION_MIN;
-+
-+ if (config_size > sizeof(VCHIQ_CONFIG_T))
-+ return VCHIQ_ERROR;
-+
-+ memcpy(pconfig, &config,
-+ min(config_size, (int)(sizeof(VCHIQ_CONFIG_T))));
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+VCHIQ_STATUS_T
-+vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
-+ VCHIQ_SERVICE_OPTION_T option, int value)
-+{
-+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+
-+ if (service) {
-+ switch (option) {
-+ case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
-+ service->auto_close = value;
-+ status = VCHIQ_SUCCESS;
-+ break;
-+
-+ case VCHIQ_SERVICE_OPTION_SLOT_QUOTA: {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &service->state->service_quotas[
-+ service->localport];
-+ if (value == 0)
-+ value = service->state->default_slot_quota;
-+ if ((value >= service_quota->slot_use_count) &&
-+ (value < (unsigned short)~0)) {
-+ service_quota->slot_quota = value;
-+ if ((value >= service_quota->slot_use_count) &&
-+ (service_quota->message_quota >=
-+ service_quota->message_use_count)) {
-+ /* Signal the service that it may have
-+ ** dropped below its quota */
-+ up(&service_quota->quota_event);
-+ }
-+ status = VCHIQ_SUCCESS;
-+ }
-+ } break;
-+
-+ case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA: {
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &service->state->service_quotas[
-+ service->localport];
-+ if (value == 0)
-+ value = service->state->default_message_quota;
-+ if ((value >= service_quota->message_use_count) &&
-+ (value < (unsigned short)~0)) {
-+ service_quota->message_quota = value;
-+ if ((value >=
-+ service_quota->message_use_count) &&
-+ (service_quota->slot_quota >=
-+ service_quota->slot_use_count))
-+ /* Signal the service that it may have
-+ ** dropped below its quota */
-+ up(&service_quota->quota_event);
-+ status = VCHIQ_SUCCESS;
-+ }
-+ } break;
-+
-+ case VCHIQ_SERVICE_OPTION_SYNCHRONOUS:
-+ if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
-+ (service->srvstate ==
-+ VCHIQ_SRVSTATE_LISTENING)) {
-+ service->sync = value;
-+ status = VCHIQ_SUCCESS;
-+ }
-+ break;
-+
-+ default:
-+ break;
-+ }
-+ unlock_service(service);
-+ }
-+
-+ return status;
-+}
-+
-+void
-+vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
-+ VCHIQ_SHARED_STATE_T *shared, const char *label)
-+{
-+ static const char *const debug_names[] = {
-+ "<entries>",
-+ "SLOT_HANDLER_COUNT",
-+ "SLOT_HANDLER_LINE",
-+ "PARSE_LINE",
-+ "PARSE_HEADER",
-+ "PARSE_MSGID",
-+ "AWAIT_COMPLETION_LINE",
-+ "DEQUEUE_MESSAGE_LINE",
-+ "SERVICE_CALLBACK_LINE",
-+ "MSG_QUEUE_FULL_COUNT",
-+ "COMPLETION_QUEUE_FULL_COUNT"
-+ };
-+ int i;
-+
-+ char buf[80];
-+ int len;
-+ len = snprintf(buf, sizeof(buf),
-+ " %s: slots %d-%d tx_pos=%x recycle=%x",
-+ label, shared->slot_first, shared->slot_last,
-+ shared->tx_pos, shared->slot_queue_recycle);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Slots claimed:");
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ for (i = shared->slot_first; i <= shared->slot_last; i++) {
-+ VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i);
-+ if (slot_info.use_count != slot_info.release_count) {
-+ len = snprintf(buf, sizeof(buf),
-+ " %d: %d/%d", i, slot_info.use_count,
-+ slot_info.release_count);
-+ vchiq_dump(dump_context, buf, len + 1);
-+ }
-+ }
-+
-+ for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++) {
-+ len = snprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
-+ debug_names[i], shared->debug[i], shared->debug[i]);
-+ vchiq_dump(dump_context, buf, len + 1);
-+ }
-+}
-+
-+void
-+vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state)
-+{
-+ char buf[80];
-+ int len;
-+ int i;
-+
-+ len = snprintf(buf, sizeof(buf), "State %d: %s", state->id,
-+ conn_state_names[state->conn_state]);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " tx_pos=%x(@%x), rx_pos=%x(@%x)",
-+ state->local->tx_pos,
-+ (uint32_t)state->tx_data +
-+ (state->local_tx_pos & VCHIQ_SLOT_MASK),
-+ state->rx_pos,
-+ (uint32_t)state->rx_data +
-+ (state->rx_pos & VCHIQ_SLOT_MASK));
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Version: %d (min %d)",
-+ VCHIQ_VERSION, VCHIQ_VERSION_MIN);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ if (VCHIQ_ENABLE_STATS) {
-+ len = snprintf(buf, sizeof(buf),
-+ " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, "
-+ "error_count=%d",
-+ state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
-+ state->stats.error_count);
-+ vchiq_dump(dump_context, buf, len + 1);
-+ }
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Slots: %d available (%d data), %d recyclable, %d stalls "
-+ "(%d data)",
-+ ((state->slot_queue_available * VCHIQ_SLOT_SIZE) -
-+ state->local_tx_pos) / VCHIQ_SLOT_SIZE,
-+ state->data_quota - state->data_use_count,
-+ state->local->slot_queue_recycle - state->slot_queue_available,
-+ state->stats.slot_stalls, state->stats.data_stalls);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ vchiq_dump_platform_state(dump_context);
-+
-+ vchiq_dump_shared_state(dump_context, state, state->local, "Local");
-+ vchiq_dump_shared_state(dump_context, state, state->remote, "Remote");
-+
-+ vchiq_dump_platform_instances(dump_context);
-+
-+ for (i = 0; i < state->unused_service; i++) {
-+ VCHIQ_SERVICE_T *service = find_service_by_port(state, i);
-+
-+ if (service) {
-+ vchiq_dump_service_state(dump_context, service);
-+ unlock_service(service);
-+ }
-+ }
-+}
-+
-+void
-+vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
-+{
-+ char buf[80];
-+ int len;
-+
-+ len = snprintf(buf, sizeof(buf), "Service %d: %s (ref %u)",
-+ service->localport, srvstate_names[service->srvstate],
-+ service->ref_count - 1); /*Don't include the lock just taken*/
-+
-+ if (service->srvstate != VCHIQ_SRVSTATE_FREE) {
-+ char remoteport[30];
-+ VCHIQ_SERVICE_QUOTA_T *service_quota =
-+ &service->state->service_quotas[service->localport];
-+ int fourcc = service->base.fourcc;
-+ int tx_pending, rx_pending;
-+ if (service->remoteport != VCHIQ_PORT_FREE) {
-+ int len2 = snprintf(remoteport, sizeof(remoteport),
-+ "%d", service->remoteport);
-+ if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
-+ snprintf(remoteport + len2,
-+ sizeof(remoteport) - len2,
-+ " (client %x)", service->client_id);
-+ } else
-+ strcpy(remoteport, "n/a");
-+
-+ len += snprintf(buf + len, sizeof(buf) - len,
-+ " '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)",
-+ VCHIQ_FOURCC_AS_4CHARS(fourcc),
-+ remoteport,
-+ service_quota->message_use_count,
-+ service_quota->message_quota,
-+ service_quota->slot_use_count,
-+ service_quota->slot_quota);
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ tx_pending = service->bulk_tx.local_insert -
-+ service->bulk_tx.remote_insert;
-+
-+ rx_pending = service->bulk_rx.local_insert -
-+ service->bulk_rx.remote_insert;
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Bulk: tx_pending=%d (size %d),"
-+ " rx_pending=%d (size %d)",
-+ tx_pending,
-+ tx_pending ? service->bulk_tx.bulks[
-+ BULK_INDEX(service->bulk_tx.remove)].size : 0,
-+ rx_pending,
-+ rx_pending ? service->bulk_rx.bulks[
-+ BULK_INDEX(service->bulk_rx.remove)].size : 0);
-+
-+ if (VCHIQ_ENABLE_STATS) {
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Ctrl: tx_count=%d, tx_bytes=%llu, "
-+ "rx_count=%d, rx_bytes=%llu",
-+ service->stats.ctrl_tx_count,
-+ service->stats.ctrl_tx_bytes,
-+ service->stats.ctrl_rx_count,
-+ service->stats.ctrl_rx_bytes);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " Bulk: tx_count=%d, tx_bytes=%llu, "
-+ "rx_count=%d, rx_bytes=%llu",
-+ service->stats.bulk_tx_count,
-+ service->stats.bulk_tx_bytes,
-+ service->stats.bulk_rx_count,
-+ service->stats.bulk_rx_bytes);
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ len = snprintf(buf, sizeof(buf),
-+ " %d quota stalls, %d slot stalls, "
-+ "%d bulk stalls, %d aborted, %d errors",
-+ service->stats.quota_stalls,
-+ service->stats.slot_stalls,
-+ service->stats.bulk_stalls,
-+ service->stats.bulk_aborted_count,
-+ service->stats.error_count);
-+ }
-+ }
-+
-+ vchiq_dump(dump_context, buf, len + 1);
-+
-+ if (service->srvstate != VCHIQ_SRVSTATE_FREE)
-+ vchiq_dump_platform_service_state(dump_context, service);
-+}
-+
-+
-+void
-+vchiq_loud_error_header(void)
-+{
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+ vchiq_log_error(vchiq_core_log_level, "=====");
-+}
-+
-+void
-+vchiq_loud_error_footer(void)
-+{
-+ vchiq_log_error(vchiq_core_log_level, "=====");
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+ vchiq_log_error(vchiq_core_log_level,
-+ "============================================================"
-+ "================");
-+}
-+
-+
-+VCHIQ_STATUS_T vchiq_send_remote_use(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_RETRY;
-+ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0),
-+ NULL, 0, 0, 0);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T vchiq_send_remote_release(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_RETRY;
-+ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0),
-+ NULL, 0, 0, 0);
-+ return status;
-+}
-+
-+VCHIQ_STATUS_T vchiq_send_remote_use_active(VCHIQ_STATE_T *state)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_RETRY;
-+ if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
-+ status = queue_message(state, NULL,
-+ VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0),
-+ NULL, 0, 0, 0);
-+ return status;
-+}
-+
-+void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem,
-+ size_t numBytes)
-+{
-+ const uint8_t *mem = (const uint8_t *)voidMem;
-+ size_t offset;
-+ char lineBuf[100];
-+ char *s;
-+
-+ while (numBytes > 0) {
-+ s = lineBuf;
-+
-+ for (offset = 0; offset < 16; offset++) {
-+ if (offset < numBytes)
-+ s += snprintf(s, 4, "%02x ", mem[offset]);
-+ else
-+ s += snprintf(s, 4, " ");
-+ }
-+
-+ for (offset = 0; offset < 16; offset++) {
-+ if (offset < numBytes) {
-+ uint8_t ch = mem[offset];
-+
-+ if ((ch < ' ') || (ch > '~'))
-+ ch = '.';
-+ *s++ = (char)ch;
-+ }
-+ }
-+ *s++ = '\0';
-+
-+ if ((label != NULL) && (*label != '\0'))
-+ vchiq_log_trace(VCHIQ_LOG_TRACE,
-+ "%s: %08x: %s", label, addr, lineBuf);
-+ else
-+ vchiq_log_trace(VCHIQ_LOG_TRACE,
-+ "%08x: %s", addr, lineBuf);
-+
-+ addr += 16;
-+ mem += 16;
-+ if (numBytes > 16)
-+ numBytes -= 16;
-+ else
-+ numBytes = 0;
-+ }
-+}
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,706 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_CORE_H
-+#define VCHIQ_CORE_H
-+
-+#include <linux/mutex.h>
-+#include <linux/semaphore.h>
-+#include <linux/kthread.h>
-+
-+#include "vchiq_cfg.h"
-+
-+#include "vchiq.h"
-+
-+/* Run time control of log level, based on KERN_XXX level. */
-+#define VCHIQ_LOG_DEFAULT 4
-+#define VCHIQ_LOG_ERROR 3
-+#define VCHIQ_LOG_WARNING 4
-+#define VCHIQ_LOG_INFO 6
-+#define VCHIQ_LOG_TRACE 7
-+
-+#define VCHIQ_LOG_PREFIX KERN_INFO "vchiq: "
-+
-+#ifndef vchiq_log_error
-+#define vchiq_log_error(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_ERROR) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+#ifndef vchiq_log_warning
-+#define vchiq_log_warning(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_WARNING) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+#ifndef vchiq_log_info
-+#define vchiq_log_info(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_INFO) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+#ifndef vchiq_log_trace
-+#define vchiq_log_trace(cat, fmt, ...) \
-+ do { if (cat >= VCHIQ_LOG_TRACE) \
-+ printk(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
-+#endif
-+
-+#define vchiq_loud_error(...) \
-+ vchiq_log_error(vchiq_core_log_level, "===== " __VA_ARGS__)
-+
-+#ifndef vchiq_static_assert
-+#define vchiq_static_assert(cond) __attribute__((unused)) \
-+ extern int vchiq_static_assert[(cond) ? 1 : -1]
-+#endif
-+
-+#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
-+
-+/* Ensure that the slot size and maximum number of slots are powers of 2 */
-+vchiq_static_assert(IS_POW2(VCHIQ_SLOT_SIZE));
-+vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS));
-+vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE));
-+
-+#define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1)
-+#define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
-+#define VCHIQ_SLOT_ZERO_SLOTS ((sizeof(VCHIQ_SLOT_ZERO_T) + \
-+ VCHIQ_SLOT_SIZE - 1) / VCHIQ_SLOT_SIZE)
-+
-+#define VCHIQ_MSG_PADDING 0 /* - */
-+#define VCHIQ_MSG_CONNECT 1 /* - */
-+#define VCHIQ_MSG_OPEN 2 /* + (srcport, -), fourcc, client_id */
-+#define VCHIQ_MSG_OPENACK 3 /* + (srcport, dstport) */
-+#define VCHIQ_MSG_CLOSE 4 /* + (srcport, dstport) */
-+#define VCHIQ_MSG_DATA 5 /* + (srcport, dstport) */
-+#define VCHIQ_MSG_BULK_RX 6 /* + (srcport, dstport), data, size */
-+#define VCHIQ_MSG_BULK_TX 7 /* + (srcport, dstport), data, size */
-+#define VCHIQ_MSG_BULK_RX_DONE 8 /* + (srcport, dstport), actual */
-+#define VCHIQ_MSG_BULK_TX_DONE 9 /* + (srcport, dstport), actual */
-+#define VCHIQ_MSG_PAUSE 10 /* - */
-+#define VCHIQ_MSG_RESUME 11 /* - */
-+#define VCHIQ_MSG_REMOTE_USE 12 /* - */
-+#define VCHIQ_MSG_REMOTE_RELEASE 13 /* - */
-+#define VCHIQ_MSG_REMOTE_USE_ACTIVE 14 /* - */
-+
-+#define VCHIQ_PORT_MAX (VCHIQ_MAX_SERVICES - 1)
-+#define VCHIQ_PORT_FREE 0x1000
-+#define VCHIQ_PORT_IS_VALID(port) (port < VCHIQ_PORT_FREE)
-+#define VCHIQ_MAKE_MSG(type, srcport, dstport) \
-+ ((type<<24) | (srcport<<12) | (dstport<<0))
-+#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)msgid >> 24)
-+#define VCHIQ_MSG_SRCPORT(msgid) \
-+ (unsigned short)(((unsigned int)msgid >> 12) & 0xfff)
-+#define VCHIQ_MSG_DSTPORT(msgid) \
-+ ((unsigned short)msgid & 0xfff)
-+
-+#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
-+ ((fourcc) >> 24) & 0xff, \
-+ ((fourcc) >> 16) & 0xff, \
-+ ((fourcc) >> 8) & 0xff, \
-+ (fourcc) & 0xff
-+
-+/* Ensure the fields are wide enough */
-+vchiq_static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX))
-+ == 0);
-+vchiq_static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0, VCHIQ_PORT_MAX, 0)) == 0);
-+vchiq_static_assert((unsigned int)VCHIQ_PORT_MAX <
-+ (unsigned int)VCHIQ_PORT_FREE);
-+
-+#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING, 0, 0)
-+#define VCHIQ_MSGID_CLAIMED 0x40000000
-+
-+#define VCHIQ_FOURCC_INVALID 0x00000000
-+#define VCHIQ_FOURCC_IS_LEGAL(fourcc) (fourcc != VCHIQ_FOURCC_INVALID)
-+
-+#define VCHIQ_BULK_ACTUAL_ABORTED -1
-+
-+typedef uint32_t BITSET_T;
-+
-+vchiq_static_assert((sizeof(BITSET_T) * 8) == 32);
-+
-+#define BITSET_SIZE(b) ((b + 31) >> 5)
-+#define BITSET_WORD(b) (b >> 5)
-+#define BITSET_BIT(b) (1 << (b & 31))
-+#define BITSET_ZERO(bs) memset(bs, 0, sizeof(bs))
-+#define BITSET_IS_SET(bs, b) (bs[BITSET_WORD(b)] & BITSET_BIT(b))
-+#define BITSET_SET(bs, b) (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
-+#define BITSET_CLR(bs, b) (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
-+
-+#if VCHIQ_ENABLE_STATS
-+#define VCHIQ_STATS_INC(state, stat) (state->stats. stat++)
-+#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat++)
-+#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) \
-+ (service->stats. stat += addend)
-+#else
-+#define VCHIQ_STATS_INC(state, stat) ((void)0)
-+#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
-+#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
-+#endif
-+
-+enum {
-+ DEBUG_ENTRIES,
-+#if VCHIQ_ENABLE_DEBUG
-+ DEBUG_SLOT_HANDLER_COUNT,
-+ DEBUG_SLOT_HANDLER_LINE,
-+ DEBUG_PARSE_LINE,
-+ DEBUG_PARSE_HEADER,
-+ DEBUG_PARSE_MSGID,
-+ DEBUG_AWAIT_COMPLETION_LINE,
-+ DEBUG_DEQUEUE_MESSAGE_LINE,
-+ DEBUG_SERVICE_CALLBACK_LINE,
-+ DEBUG_MSG_QUEUE_FULL_COUNT,
-+ DEBUG_COMPLETION_QUEUE_FULL_COUNT,
-+#endif
-+ DEBUG_MAX
-+};
-+
-+#if VCHIQ_ENABLE_DEBUG
-+
-+#define DEBUG_INITIALISE(local) int *debug_ptr = (local)->debug;
-+#define DEBUG_TRACE(d) \
-+ do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(); } while (0)
-+#define DEBUG_VALUE(d, v) \
-+ do { debug_ptr[DEBUG_ ## d] = (v); dsb(); } while (0)
-+#define DEBUG_COUNT(d) \
-+ do { debug_ptr[DEBUG_ ## d]++; dsb(); } while (0)
-+
-+#else /* VCHIQ_ENABLE_DEBUG */
-+
-+#define DEBUG_INITIALISE(local)
-+#define DEBUG_TRACE(d)
-+#define DEBUG_VALUE(d, v)
-+#define DEBUG_COUNT(d)
-+
-+#endif /* VCHIQ_ENABLE_DEBUG */
-+
-+typedef enum {
-+ VCHIQ_CONNSTATE_DISCONNECTED,
-+ VCHIQ_CONNSTATE_CONNECTING,
-+ VCHIQ_CONNSTATE_CONNECTED,
-+ VCHIQ_CONNSTATE_PAUSING,
-+ VCHIQ_CONNSTATE_PAUSE_SENT,
-+ VCHIQ_CONNSTATE_PAUSED,
-+ VCHIQ_CONNSTATE_RESUMING,
-+ VCHIQ_CONNSTATE_PAUSE_TIMEOUT,
-+ VCHIQ_CONNSTATE_RESUME_TIMEOUT
-+} VCHIQ_CONNSTATE_T;
-+
-+enum {
-+ VCHIQ_SRVSTATE_FREE,
-+ VCHIQ_SRVSTATE_HIDDEN,
-+ VCHIQ_SRVSTATE_LISTENING,
-+ VCHIQ_SRVSTATE_OPENING,
-+ VCHIQ_SRVSTATE_OPEN,
-+ VCHIQ_SRVSTATE_OPENSYNC,
-+ VCHIQ_SRVSTATE_CLOSESENT,
-+ VCHIQ_SRVSTATE_CLOSERECVD,
-+ VCHIQ_SRVSTATE_CLOSEWAIT,
-+ VCHIQ_SRVSTATE_CLOSED
-+};
-+
-+enum {
-+ VCHIQ_POLL_TERMINATE,
-+ VCHIQ_POLL_REMOVE,
-+ VCHIQ_POLL_TXNOTIFY,
-+ VCHIQ_POLL_RXNOTIFY,
-+ VCHIQ_POLL_COUNT
-+};
-+
-+typedef enum {
-+ VCHIQ_BULK_TRANSMIT,
-+ VCHIQ_BULK_RECEIVE
-+} VCHIQ_BULK_DIR_T;
-+
-+typedef void (*VCHIQ_USERDATA_TERM_T)(void *userdata);
-+
-+typedef struct vchiq_bulk_struct {
-+ short mode;
-+ short dir;
-+ void *userdata;
-+ VCHI_MEM_HANDLE_T handle;
-+ void *data;
-+ int size;
-+ void *remote_data;
-+ int remote_size;
-+ int actual;
-+} VCHIQ_BULK_T;
-+
-+typedef struct vchiq_bulk_queue_struct {
-+ int local_insert; /* Where to insert the next local bulk */
-+ int remote_insert; /* Where to insert the next remote bulk (master) */
-+ int process; /* Bulk to transfer next */
-+ int remote_notify; /* Bulk to notify the remote client of next (mstr) */
-+ int remove; /* Bulk to notify the local client of, and remove,
-+ ** next */
-+ VCHIQ_BULK_T bulks[VCHIQ_NUM_SERVICE_BULKS];
-+} VCHIQ_BULK_QUEUE_T;
-+
-+typedef struct remote_event_struct {
-+ int armed;
-+ int fired;
-+ struct semaphore *event;
-+} REMOTE_EVENT_T;
-+
-+typedef struct opaque_platform_state_t *VCHIQ_PLATFORM_STATE_T;
-+
-+typedef struct vchiq_state_struct VCHIQ_STATE_T;
-+
-+typedef struct vchiq_slot_struct {
-+ char data[VCHIQ_SLOT_SIZE];
-+} VCHIQ_SLOT_T;
-+
-+typedef struct vchiq_slot_info_struct {
-+ /* Use two counters rather than one to avoid the need for a mutex. */
-+ short use_count;
-+ short release_count;
-+} VCHIQ_SLOT_INFO_T;
-+
-+typedef struct vchiq_service_struct {
-+ VCHIQ_SERVICE_BASE_T base;
-+ VCHIQ_SERVICE_HANDLE_T handle;
-+ unsigned int ref_count;
-+ int srvstate;
-+ VCHIQ_USERDATA_TERM_T userdata_term;
-+ unsigned int localport;
-+ unsigned int remoteport;
-+ int public_fourcc;
-+ int client_id;
-+ char auto_close;
-+ char sync;
-+ char closing;
-+ atomic_t poll_flags;
-+ short version;
-+ short version_min;
-+ short peer_version;
-+
-+ VCHIQ_STATE_T *state;
-+ VCHIQ_INSTANCE_T instance;
-+
-+ int service_use_count;
-+
-+ VCHIQ_BULK_QUEUE_T bulk_tx;
-+ VCHIQ_BULK_QUEUE_T bulk_rx;
-+
-+ struct semaphore remove_event;
-+ struct semaphore bulk_remove_event;
-+ struct mutex bulk_mutex;
-+
-+ struct service_stats_struct {
-+ int quota_stalls;
-+ int slot_stalls;
-+ int bulk_stalls;
-+ int error_count;
-+ int ctrl_tx_count;
-+ int ctrl_rx_count;
-+ int bulk_tx_count;
-+ int bulk_rx_count;
-+ int bulk_aborted_count;
-+ uint64_t ctrl_tx_bytes;
-+ uint64_t ctrl_rx_bytes;
-+ uint64_t bulk_tx_bytes;
-+ uint64_t bulk_rx_bytes;
-+ } stats;
-+} VCHIQ_SERVICE_T;
-+
-+/* The quota information is outside VCHIQ_SERVICE_T so that it can be
-+ statically allocated, since for accounting reasons a service's slot
-+ usage is carried over between users of the same port number.
-+ */
-+typedef struct vchiq_service_quota_struct {
-+ unsigned short slot_quota;
-+ unsigned short slot_use_count;
-+ unsigned short message_quota;
-+ unsigned short message_use_count;
-+ struct semaphore quota_event;
-+ int previous_tx_index;
-+} VCHIQ_SERVICE_QUOTA_T;
-+
-+typedef struct vchiq_shared_state_struct {
-+
-+ /* A non-zero value here indicates that the content is valid. */
-+ int initialised;
-+
-+ /* The first and last (inclusive) slots allocated to the owner. */
-+ int slot_first;
-+ int slot_last;
-+
-+ /* The slot allocated to synchronous messages from the owner. */
-+ int slot_sync;
-+
-+ /* Signalling this event indicates that owner's slot handler thread
-+ ** should run. */
-+ REMOTE_EVENT_T trigger;
-+
-+ /* Indicates the byte position within the stream where the next message
-+ ** will be written. The least significant bits are an index into the
-+ ** slot. The next bits are the index of the slot in slot_queue. */
-+ int tx_pos;
-+
-+ /* This event should be signalled when a slot is recycled. */
-+ REMOTE_EVENT_T recycle;
-+
-+ /* The slot_queue index where the next recycled slot will be written. */
-+ int slot_queue_recycle;
-+
-+ /* This event should be signalled when a synchronous message is sent. */
-+ REMOTE_EVENT_T sync_trigger;
-+
-+ /* This event should be signalled when a synchronous message has been
-+ ** released. */
-+ REMOTE_EVENT_T sync_release;
-+
-+ /* A circular buffer of slot indexes. */
-+ int slot_queue[VCHIQ_MAX_SLOTS_PER_SIDE];
-+
-+ /* Debugging state */
-+ int debug[DEBUG_MAX];
-+} VCHIQ_SHARED_STATE_T;
-+
-+typedef struct vchiq_slot_zero_struct {
-+ int magic;
-+ short version;
-+ short version_min;
-+ int slot_zero_size;
-+ int slot_size;
-+ int max_slots;
-+ int max_slots_per_side;
-+ int platform_data[2];
-+ VCHIQ_SHARED_STATE_T master;
-+ VCHIQ_SHARED_STATE_T slave;
-+ VCHIQ_SLOT_INFO_T slots[VCHIQ_MAX_SLOTS];
-+} VCHIQ_SLOT_ZERO_T;
-+
-+struct vchiq_state_struct {
-+ int id;
-+ int initialised;
-+ VCHIQ_CONNSTATE_T conn_state;
-+ int is_master;
-+
-+ VCHIQ_SHARED_STATE_T *local;
-+ VCHIQ_SHARED_STATE_T *remote;
-+ VCHIQ_SLOT_T *slot_data;
-+
-+ unsigned short default_slot_quota;
-+ unsigned short default_message_quota;
-+
-+ /* Event indicating connect message received */
-+ struct semaphore connect;
-+
-+ /* Mutex protecting services */
-+ struct mutex mutex;
-+ VCHIQ_INSTANCE_T *instance;
-+
-+ /* Processes incoming messages */
-+ struct task_struct *slot_handler_thread;
-+
-+ /* Processes recycled slots */
-+ struct task_struct *recycle_thread;
-+
-+ /* Processes synchronous messages */
-+ struct task_struct *sync_thread;
-+
-+ /* Local implementation of the trigger remote event */
-+ struct semaphore trigger_event;
-+
-+ /* Local implementation of the recycle remote event */
-+ struct semaphore recycle_event;
-+
-+ /* Local implementation of the sync trigger remote event */
-+ struct semaphore sync_trigger_event;
-+
-+ /* Local implementation of the sync release remote event */
-+ struct semaphore sync_release_event;
-+
-+ char *tx_data;
-+ char *rx_data;
-+ VCHIQ_SLOT_INFO_T *rx_info;
-+
-+ struct mutex slot_mutex;
-+
-+ struct mutex recycle_mutex;
-+
-+ struct mutex sync_mutex;
-+
-+ struct mutex bulk_transfer_mutex;
-+
-+ /* Indicates the byte position within the stream from where the next
-+ ** message will be read. The least significant bits are an index into
-+ ** the slot.The next bits are the index of the slot in
-+ ** remote->slot_queue. */
-+ int rx_pos;
-+
-+ /* A cached copy of local->tx_pos. Only write to local->tx_pos, and read
-+ from remote->tx_pos. */
-+ int local_tx_pos;
-+
-+ /* The slot_queue index of the slot to become available next. */
-+ int slot_queue_available;
-+
-+ /* A flag to indicate if any poll has been requested */
-+ int poll_needed;
-+
-+ /* Ths index of the previous slot used for data messages. */
-+ int previous_data_index;
-+
-+ /* The number of slots occupied by data messages. */
-+ unsigned short data_use_count;
-+
-+ /* The maximum number of slots to be occupied by data messages. */
-+ unsigned short data_quota;
-+
-+ /* An array of bit sets indicating which services must be polled. */
-+ atomic_t poll_services[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
-+
-+ /* The number of the first unused service */
-+ int unused_service;
-+
-+ /* Signalled when a free slot becomes available. */
-+ struct semaphore slot_available_event;
-+
-+ struct semaphore slot_remove_event;
-+
-+ /* Signalled when a free data slot becomes available. */
-+ struct semaphore data_quota_event;
-+
-+ /* Incremented when there are bulk transfers which cannot be processed
-+ * whilst paused and must be processed on resume */
-+ int deferred_bulks;
-+
-+ struct state_stats_struct {
-+ int slot_stalls;
-+ int data_stalls;
-+ int ctrl_tx_count;
-+ int ctrl_rx_count;
-+ int error_count;
-+ } stats;
-+
-+ VCHIQ_SERVICE_T * services[VCHIQ_MAX_SERVICES];
-+ VCHIQ_SERVICE_QUOTA_T service_quotas[VCHIQ_MAX_SERVICES];
-+ VCHIQ_SLOT_INFO_T slot_info[VCHIQ_MAX_SLOTS];
-+
-+ VCHIQ_PLATFORM_STATE_T platform_state;
-+};
-+
-+struct bulk_waiter {
-+ VCHIQ_BULK_T *bulk;
-+ struct semaphore event;
-+ int actual;
-+};
-+
-+extern spinlock_t bulk_waiter_spinlock;
-+
-+extern int vchiq_core_log_level;
-+extern int vchiq_core_msg_log_level;
-+extern int vchiq_sync_log_level;
-+
-+extern VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
-+
-+extern const char *
-+get_conn_state_name(VCHIQ_CONNSTATE_T conn_state);
-+
-+extern VCHIQ_SLOT_ZERO_T *
-+vchiq_init_slots(void *mem_base, int mem_size);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
-+ int is_master);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
-+
-+extern VCHIQ_SERVICE_T *
-+vchiq_add_service_internal(VCHIQ_STATE_T *state,
-+ const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
-+ VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd);
-+
-+extern void
-+vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_free_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_pause_internal(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_resume_internal(VCHIQ_STATE_T *state);
-+
-+extern void
-+remote_event_pollall(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
-+ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir);
-+
-+extern void
-+vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_loud_error_header(void);
-+
-+extern void
-+vchiq_loud_error_footer(void);
-+
-+extern void
-+request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type);
-+
-+static inline VCHIQ_SERVICE_T *
-+handle_to_service(VCHIQ_SERVICE_HANDLE_T handle)
-+{
-+ VCHIQ_STATE_T *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) &
-+ (VCHIQ_MAX_STATES - 1)];
-+ if (!state)
-+ return NULL;
-+
-+ return state->services[handle & (VCHIQ_MAX_SERVICES - 1)];
-+}
-+
-+extern VCHIQ_SERVICE_T *
-+find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_SERVICE_T *
-+find_service_by_port(VCHIQ_STATE_T *state, int localport);
-+
-+extern VCHIQ_SERVICE_T *
-+find_service_for_instance(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_SERVICE_HANDLE_T handle);
-+
-+extern VCHIQ_SERVICE_T *
-+next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
-+ int *pidx);
-+
-+extern void
-+lock_service(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+unlock_service(VCHIQ_SERVICE_T *service);
-+
-+/* The following functions are called from vchiq_core, and external
-+** implementations must be provided. */
-+
-+extern VCHIQ_STATUS_T
-+vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk,
-+ VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir);
-+
-+extern void
-+vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
-+
-+extern void
-+vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_copy_from_user(void *dst, const void *src, int size);
-+
-+extern void
-+remote_event_signal(REMOTE_EVENT_T *event);
-+
-+void
-+vchiq_platform_check_suspend(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_platform_paused(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_platform_resume(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_platform_resumed(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_dump(void *dump_context, const char *str, int len);
-+
-+extern void
-+vchiq_dump_platform_state(void *dump_context);
-+
-+extern void
-+vchiq_dump_platform_instances(void *dump_context);
-+
-+extern void
-+vchiq_dump_platform_service_state(void *dump_context,
-+ VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_use_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_release_service_internal(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_on_remote_use(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_on_remote_release(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_platform_init_state(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_check_service(VCHIQ_SERVICE_T *service);
-+
-+extern void
-+vchiq_on_remote_use_active(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_send_remote_use(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_send_remote_release(VCHIQ_STATE_T *state);
-+
-+extern VCHIQ_STATUS_T
-+vchiq_send_remote_use_active(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
-+ VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate);
-+
-+extern void
-+vchiq_platform_handle_timeout(VCHIQ_STATE_T *state);
-+
-+extern void
-+vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate);
-+
-+
-+extern void
-+vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem,
-+ size_t numBytes);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_genversion 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,87 @@
-+#!/usr/bin/perl -w
-+
-+use strict;
-+
-+#
-+# Generate a version from available information
-+#
-+
-+my $prefix = shift @ARGV;
-+my $root = shift @ARGV;
-+
-+
-+if ( not defined $root ) {
-+ die "usage: $0 prefix root-dir\n";
-+}
-+
-+if ( ! -d $root ) {
-+ die "root directory $root not found\n";
-+}
-+
-+my $version = "unknown";
-+my $tainted = "";
-+
-+if ( -d "$root/.git" ) {
-+ # attempt to work out git version. only do so
-+ # on a linux build host, as cygwin builds are
-+ # already slow enough
-+
-+ if ( -f "/usr/bin/git" || -f "/usr/local/bin/git" ) {
-+ if (not open(F, "git --git-dir $root/.git rev-parse --verify HEAD|")) {
-+ $version = "no git version";
-+ }
-+ else {
-+ $version = <F>;
-+ $version =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-+ $version =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-+ }
-+
-+ if (open(G, "git --git-dir $root/.git status --porcelain|")) {
-+ $tainted = <G>;
-+ $tainted =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-+ $tainted =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-+ if (length $tainted) {
-+ $version = join ' ', $version, "(tainted)";
-+ }
-+ else {
-+ $version = join ' ', $version, "(clean)";
-+ }
-+ }
-+ }
-+}
-+
-+my $hostname = `hostname`;
-+$hostname =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-+$hostname =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-+
-+
-+print STDERR "Version $version\n";
-+print <<EOF;
-+#include "${prefix}_build_info.h"
-+#include <linux/broadcom/vc_debug_sym.h>
-+
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_hostname, "$hostname" );
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_version, "$version" );
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_time, __TIME__ );
-+VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_date, __DATE__ );
-+
-+const char *vchiq_get_build_hostname( void )
-+{
-+ return vchiq_build_hostname;
-+}
-+
-+const char *vchiq_get_build_version( void )
-+{
-+ return vchiq_build_version;
-+}
-+
-+const char *vchiq_get_build_date( void )
-+{
-+ return vchiq_build_date;
-+}
-+
-+const char *vchiq_get_build_time( void )
-+{
-+ return vchiq_build_time;
-+}
-+EOF
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,40 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_VCHIQ_H
-+#define VCHIQ_VCHIQ_H
-+
-+#include "vchiq_if.h"
-+#include "vchiq_util.h"
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,188 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_IF_H
-+#define VCHIQ_IF_H
-+
-+#include "interface/vchi/vchi_mh.h"
-+
-+#define VCHIQ_SERVICE_HANDLE_INVALID 0
-+
-+#define VCHIQ_SLOT_SIZE 4096
-+#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
-+#define VCHIQ_CHANNEL_SIZE VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
-+
-+#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) \
-+ (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
-+#define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service)
-+#define VCHIQ_GET_SERVICE_FOURCC(service) vchiq_get_service_fourcc(service)
-+
-+typedef enum {
-+ VCHIQ_SERVICE_OPENED, /* service, -, - */
-+ VCHIQ_SERVICE_CLOSED, /* service, -, - */
-+ VCHIQ_MESSAGE_AVAILABLE, /* service, header, - */
-+ VCHIQ_BULK_TRANSMIT_DONE, /* service, -, bulk_userdata */
-+ VCHIQ_BULK_RECEIVE_DONE, /* service, -, bulk_userdata */
-+ VCHIQ_BULK_TRANSMIT_ABORTED, /* service, -, bulk_userdata */
-+ VCHIQ_BULK_RECEIVE_ABORTED /* service, -, bulk_userdata */
-+} VCHIQ_REASON_T;
-+
-+typedef enum {
-+ VCHIQ_ERROR = -1,
-+ VCHIQ_SUCCESS = 0,
-+ VCHIQ_RETRY = 1
-+} VCHIQ_STATUS_T;
-+
-+typedef enum {
-+ VCHIQ_BULK_MODE_CALLBACK,
-+ VCHIQ_BULK_MODE_BLOCKING,
-+ VCHIQ_BULK_MODE_NOCALLBACK,
-+ VCHIQ_BULK_MODE_WAITING /* Reserved for internal use */
-+} VCHIQ_BULK_MODE_T;
-+
-+typedef enum {
-+ VCHIQ_SERVICE_OPTION_AUTOCLOSE,
-+ VCHIQ_SERVICE_OPTION_SLOT_QUOTA,
-+ VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA,
-+ VCHIQ_SERVICE_OPTION_SYNCHRONOUS
-+} VCHIQ_SERVICE_OPTION_T;
-+
-+typedef struct vchiq_header_struct {
-+ /* The message identifier - opaque to applications. */
-+ int msgid;
-+
-+ /* Size of message data. */
-+ unsigned int size;
-+
-+ char data[0]; /* message */
-+} VCHIQ_HEADER_T;
-+
-+typedef struct {
-+ const void *data;
-+ unsigned int size;
-+} VCHIQ_ELEMENT_T;
-+
-+typedef unsigned int VCHIQ_SERVICE_HANDLE_T;
-+
-+typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *,
-+ VCHIQ_SERVICE_HANDLE_T, void *);
-+
-+typedef struct vchiq_service_base_struct {
-+ int fourcc;
-+ VCHIQ_CALLBACK_T callback;
-+ void *userdata;
-+} VCHIQ_SERVICE_BASE_T;
-+
-+typedef struct vchiq_service_params_struct {
-+ int fourcc;
-+ VCHIQ_CALLBACK_T callback;
-+ void *userdata;
-+ short version; /* Increment for non-trivial changes */
-+ short version_min; /* Update for incompatible changes */
-+} VCHIQ_SERVICE_PARAMS_T;
-+
-+typedef struct vchiq_config_struct {
-+ unsigned int max_msg_size;
-+ unsigned int bulk_threshold; /* The message size above which it
-+ is better to use a bulk transfer
-+ (<= max_msg_size) */
-+ unsigned int max_outstanding_bulks;
-+ unsigned int max_services;
-+ short version; /* The version of VCHIQ */
-+ short version_min; /* The minimum compatible version of VCHIQ */
-+} VCHIQ_CONFIG_T;
-+
-+typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
-+typedef void (*VCHIQ_REMOTE_USE_CALLBACK_T)(void *cb_arg);
-+
-+extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
-+extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
-+extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
-+extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *pservice);
-+extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *pservice);
-+extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_use_service_no_resume(
-+ VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
-+
-+extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service,
-+ const VCHIQ_ELEMENT_T *elements, unsigned int count);
-+extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHIQ_HEADER_T *header);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
-+ const void *data, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
-+ void *data, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(
-+ VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
-+ const void *offset, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(
-+ VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
-+ void *offset, unsigned int size, void *userdata);
-+extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
-+ const void *data, unsigned int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode);
-+extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
-+ void *data, unsigned int size, void *userdata,
-+ VCHIQ_BULK_MODE_T mode);
-+extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHI_MEM_HANDLE_T handle, const void *offset, unsigned int size,
-+ void *userdata, VCHIQ_BULK_MODE_T mode);
-+extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHI_MEM_HANDLE_T handle, void *offset, unsigned int size,
-+ void *userdata, VCHIQ_BULK_MODE_T mode);
-+extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
-+extern void *vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T service);
-+extern int vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T service);
-+extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance,
-+ int config_size, VCHIQ_CONFIG_T *pconfig);
-+extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service,
-+ VCHIQ_SERVICE_OPTION_T option, int value);
-+
-+extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance,
-+ VCHIQ_REMOTE_USE_CALLBACK_T callback, void *cb_arg);
-+extern VCHIQ_STATUS_T vchiq_remote_release(VCHIQ_INSTANCE_T instance);
-+
-+extern VCHIQ_STATUS_T vchiq_dump_phys_mem(VCHIQ_SERVICE_HANDLE_T service,
-+ void *ptr, size_t num_bytes);
-+
-+extern VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle,
-+ short *peer_version);
-+
-+#endif /* VCHIQ_IF_H */
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,129 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_IOCTLS_H
-+#define VCHIQ_IOCTLS_H
-+
-+#include <linux/ioctl.h>
-+#include "vchiq_if.h"
-+
-+#define VCHIQ_IOC_MAGIC 0xc4
-+#define VCHIQ_INVALID_HANDLE (~0)
-+
-+typedef struct {
-+ VCHIQ_SERVICE_PARAMS_T params;
-+ int is_open;
-+ int is_vchi;
-+ unsigned int handle; /* OUT */
-+} VCHIQ_CREATE_SERVICE_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ unsigned int count;
-+ const VCHIQ_ELEMENT_T *elements;
-+} VCHIQ_QUEUE_MESSAGE_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ void *data;
-+ unsigned int size;
-+ void *userdata;
-+ VCHIQ_BULK_MODE_T mode;
-+} VCHIQ_QUEUE_BULK_TRANSFER_T;
-+
-+typedef struct {
-+ VCHIQ_REASON_T reason;
-+ VCHIQ_HEADER_T *header;
-+ void *service_userdata;
-+ void *bulk_userdata;
-+} VCHIQ_COMPLETION_DATA_T;
-+
-+typedef struct {
-+ unsigned int count;
-+ VCHIQ_COMPLETION_DATA_T *buf;
-+ unsigned int msgbufsize;
-+ unsigned int msgbufcount; /* IN/OUT */
-+ void **msgbufs;
-+} VCHIQ_AWAIT_COMPLETION_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ int blocking;
-+ unsigned int bufsize;
-+ void *buf;
-+} VCHIQ_DEQUEUE_MESSAGE_T;
-+
-+typedef struct {
-+ unsigned int config_size;
-+ VCHIQ_CONFIG_T *pconfig;
-+} VCHIQ_GET_CONFIG_T;
-+
-+typedef struct {
-+ unsigned int handle;
-+ VCHIQ_SERVICE_OPTION_T option;
-+ int value;
-+} VCHIQ_SET_SERVICE_OPTION_T;
-+
-+typedef struct {
-+ void *virt_addr;
-+ size_t num_bytes;
-+} VCHIQ_DUMP_MEM_T;
-+
-+#define VCHIQ_IOC_CONNECT _IO(VCHIQ_IOC_MAGIC, 0)
-+#define VCHIQ_IOC_SHUTDOWN _IO(VCHIQ_IOC_MAGIC, 1)
-+#define VCHIQ_IOC_CREATE_SERVICE \
-+ _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
-+#define VCHIQ_IOC_REMOVE_SERVICE _IO(VCHIQ_IOC_MAGIC, 3)
-+#define VCHIQ_IOC_QUEUE_MESSAGE \
-+ _IOW(VCHIQ_IOC_MAGIC, 4, VCHIQ_QUEUE_MESSAGE_T)
-+#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT \
-+ _IOWR(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
-+#define VCHIQ_IOC_QUEUE_BULK_RECEIVE \
-+ _IOWR(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
-+#define VCHIQ_IOC_AWAIT_COMPLETION \
-+ _IOWR(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T)
-+#define VCHIQ_IOC_DEQUEUE_MESSAGE \
-+ _IOWR(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T)
-+#define VCHIQ_IOC_GET_CLIENT_ID _IO(VCHIQ_IOC_MAGIC, 9)
-+#define VCHIQ_IOC_GET_CONFIG \
-+ _IOWR(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T)
-+#define VCHIQ_IOC_CLOSE_SERVICE _IO(VCHIQ_IOC_MAGIC, 11)
-+#define VCHIQ_IOC_USE_SERVICE _IO(VCHIQ_IOC_MAGIC, 12)
-+#define VCHIQ_IOC_RELEASE_SERVICE _IO(VCHIQ_IOC_MAGIC, 13)
-+#define VCHIQ_IOC_SET_SERVICE_OPTION \
-+ _IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T)
-+#define VCHIQ_IOC_DUMP_PHYS_MEM \
-+ _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T)
-+#define VCHIQ_IOC_MAX 15
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,456 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+/* ---- Include Files ---------------------------------------------------- */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+
-+#include "vchiq_core.h"
-+#include "vchiq_arm.h"
-+
-+/* ---- Public Variables ------------------------------------------------- */
-+
-+/* ---- Private Constants and Types -------------------------------------- */
-+
-+struct bulk_waiter_node {
-+ struct bulk_waiter bulk_waiter;
-+ int pid;
-+ struct list_head list;
-+};
-+
-+struct vchiq_instance_struct {
-+ VCHIQ_STATE_T *state;
-+
-+ int connected;
-+
-+ struct list_head bulk_waiter_list;
-+ struct mutex bulk_waiter_list_mutex;
-+};
-+
-+static VCHIQ_STATUS_T
-+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, VCHIQ_BULK_DIR_T dir);
-+
-+/****************************************************************************
-+*
-+* vchiq_initialise
-+*
-+***************************************************************************/
-+#define VCHIQ_INIT_RETRIES 10
-+VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instanceOut)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_STATE_T *state;
-+ VCHIQ_INSTANCE_T instance = NULL;
-+ int i;
-+
-+ vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
-+
-+ /* VideoCore may not be ready due to boot up timing.
-+ It may never be ready if kernel and firmware are mismatched, so don't block forever. */
-+ for (i=0; i<VCHIQ_INIT_RETRIES; i++) {
-+ state = vchiq_get_state();
-+ if (state)
-+ break;
-+ udelay(500);
-+ }
-+ if (i==VCHIQ_INIT_RETRIES) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%s: videocore not initialized\n", __func__);
-+ goto failed;
-+ } else if (i>0) {
-+ vchiq_log_warning(vchiq_core_log_level,
-+ "%s: videocore initialized after %d retries\n", __func__, i);
-+ }
-+
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+ if (!instance) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%s: error allocating vchiq instance\n", __func__);
-+ goto failed;
-+ }
-+
-+ instance->connected = 0;
-+ instance->state = state;
-+ mutex_init(&instance->bulk_waiter_list_mutex);
-+ INIT_LIST_HEAD(&instance->bulk_waiter_list);
-+
-+ *instanceOut = instance;
-+
-+ status = VCHIQ_SUCCESS;
-+
-+failed:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_initialise);
-+
-+/****************************************************************************
-+*
-+* vchiq_shutdown
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_STATE_T *state = instance->state;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ if (mutex_lock_interruptible(&state->mutex) != 0)
-+ return VCHIQ_RETRY;
-+
-+ /* Remove all services */
-+ status = vchiq_shutdown_internal(state, instance);
-+
-+ mutex_unlock(&state->mutex);
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ if (status == VCHIQ_SUCCESS) {
-+ struct list_head *pos, *next;
-+ list_for_each_safe(pos, next,
-+ &instance->bulk_waiter_list) {
-+ struct bulk_waiter_node *waiter;
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "bulk_waiter - cleaned up %x "
-+ "for pid %d",
-+ (unsigned int)waiter, waiter->pid);
-+ kfree(waiter);
-+ }
-+ kfree(instance);
-+ }
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_shutdown);
-+
-+/****************************************************************************
-+*
-+* vchiq_is_connected
-+*
-+***************************************************************************/
-+
-+int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
-+{
-+ return instance->connected;
-+}
-+
-+/****************************************************************************
-+*
-+* vchiq_connect
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
-+{
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_STATE_T *state = instance->state;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ if (mutex_lock_interruptible(&state->mutex) != 0) {
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s: call to mutex_lock failed", __func__);
-+ status = VCHIQ_RETRY;
-+ goto failed;
-+ }
-+ status = vchiq_connect_internal(state, instance);
-+
-+ if (status == VCHIQ_SUCCESS)
-+ instance->connected = 1;
-+
-+ mutex_unlock(&state->mutex);
-+
-+failed:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_connect);
-+
-+/****************************************************************************
-+*
-+* vchiq_add_service
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_add_service(
-+ VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *phandle)
-+{
-+ VCHIQ_STATUS_T status;
-+ VCHIQ_STATE_T *state = instance->state;
-+ VCHIQ_SERVICE_T *service = NULL;
-+ int srvstate;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-+
-+ srvstate = vchiq_is_connected(instance)
-+ ? VCHIQ_SRVSTATE_LISTENING
-+ : VCHIQ_SRVSTATE_HIDDEN;
-+
-+ service = vchiq_add_service_internal(
-+ state,
-+ params,
-+ srvstate,
-+ instance,
-+ NULL);
-+
-+ if (service) {
-+ *phandle = service->handle;
-+ status = VCHIQ_SUCCESS;
-+ } else
-+ status = VCHIQ_ERROR;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_add_service);
-+
-+/****************************************************************************
-+*
-+* vchiq_open_service
-+*
-+***************************************************************************/
-+
-+VCHIQ_STATUS_T vchiq_open_service(
-+ VCHIQ_INSTANCE_T instance,
-+ const VCHIQ_SERVICE_PARAMS_T *params,
-+ VCHIQ_SERVICE_HANDLE_T *phandle)
-+{
-+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
-+ VCHIQ_STATE_T *state = instance->state;
-+ VCHIQ_SERVICE_T *service = NULL;
-+
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p) called", __func__, instance);
-+
-+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-+
-+ if (!vchiq_is_connected(instance))
-+ goto failed;
-+
-+ service = vchiq_add_service_internal(state,
-+ params,
-+ VCHIQ_SRVSTATE_OPENING,
-+ instance,
-+ NULL);
-+
-+ if (service) {
-+ status = vchiq_open_service_internal(service, current->pid);
-+ if (status == VCHIQ_SUCCESS)
-+ *phandle = service->handle;
-+ else
-+ vchiq_remove_service(service->handle);
-+ }
-+
-+failed:
-+ vchiq_log_trace(vchiq_core_log_level,
-+ "%s(%p): returning %d", __func__, instance, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_open_service);
-+
-+VCHIQ_STATUS_T
-+vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
-+ const void *data, unsigned int size, void *userdata)
-+{
-+ return vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
-+ VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
-+}
-+EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
-+
-+VCHIQ_STATUS_T
-+vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, void *userdata)
-+{
-+ return vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
-+ VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
-+}
-+EXPORT_SYMBOL(vchiq_queue_bulk_receive);
-+
-+VCHIQ_STATUS_T
-+vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
-+ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-+{
-+ VCHIQ_STATUS_T status;
-+
-+ switch (mode) {
-+ case VCHIQ_BULK_MODE_NOCALLBACK:
-+ case VCHIQ_BULK_MODE_CALLBACK:
-+ status = vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
-+ mode, VCHIQ_BULK_TRANSMIT);
-+ break;
-+ case VCHIQ_BULK_MODE_BLOCKING:
-+ status = vchiq_blocking_bulk_transfer(handle,
-+ (void *)data, size, VCHIQ_BULK_TRANSMIT);
-+ break;
-+ default:
-+ return VCHIQ_ERROR;
-+ }
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_bulk_transmit);
-+
-+VCHIQ_STATUS_T
-+vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-+{
-+ VCHIQ_STATUS_T status;
-+
-+ switch (mode) {
-+ case VCHIQ_BULK_MODE_NOCALLBACK:
-+ case VCHIQ_BULK_MODE_CALLBACK:
-+ status = vchiq_bulk_transfer(handle,
-+ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
-+ mode, VCHIQ_BULK_RECEIVE);
-+ break;
-+ case VCHIQ_BULK_MODE_BLOCKING:
-+ status = vchiq_blocking_bulk_transfer(handle,
-+ (void *)data, size, VCHIQ_BULK_RECEIVE);
-+ break;
-+ default:
-+ return VCHIQ_ERROR;
-+ }
-+
-+ return status;
-+}
-+EXPORT_SYMBOL(vchiq_bulk_receive);
-+
-+static VCHIQ_STATUS_T
-+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-+ unsigned int size, VCHIQ_BULK_DIR_T dir)
-+{
-+ VCHIQ_INSTANCE_T instance;
-+ VCHIQ_SERVICE_T *service;
-+ VCHIQ_STATUS_T status;
-+ struct bulk_waiter_node *waiter = NULL;
-+ struct list_head *pos;
-+
-+ service = find_service_by_handle(handle);
-+ if (!service)
-+ return VCHIQ_ERROR;
-+
-+ instance = service->instance;
-+
-+ unlock_service(service);
-+
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_for_each(pos, &instance->bulk_waiter_list) {
-+ if (list_entry(pos, struct bulk_waiter_node,
-+ list)->pid == current->pid) {
-+ waiter = list_entry(pos,
-+ struct bulk_waiter_node,
-+ list);
-+ list_del(pos);
-+ break;
-+ }
-+ }
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+
-+ if (waiter) {
-+ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-+ if (bulk) {
-+ /* This thread has an outstanding bulk transfer. */
-+ if ((bulk->data != data) ||
-+ (bulk->size != size)) {
-+ /* This is not a retry of the previous one.
-+ ** Cancel the signal when the transfer
-+ ** completes. */
-+ spin_lock(&bulk_waiter_spinlock);
-+ bulk->userdata = NULL;
-+ spin_unlock(&bulk_waiter_spinlock);
-+ }
-+ }
-+ }
-+
-+ if (!waiter) {
-+ waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
-+ if (!waiter) {
-+ vchiq_log_error(vchiq_core_log_level,
-+ "%s - out of memory", __func__);
-+ return VCHIQ_ERROR;
-+ }
-+ }
-+
-+ status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
-+ data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
-+ dir);
-+ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
-+ !waiter->bulk_waiter.bulk) {
-+ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-+ if (bulk) {
-+ /* Cancel the signal when the transfer
-+ ** completes. */
-+ spin_lock(&bulk_waiter_spinlock);
-+ bulk->userdata = NULL;
-+ spin_unlock(&bulk_waiter_spinlock);
-+ }
-+ kfree(waiter);
-+ } else {
-+ waiter->pid = current->pid;
-+ mutex_lock(&instance->bulk_waiter_list_mutex);
-+ list_add(&waiter->list, &instance->bulk_waiter_list);
-+ mutex_unlock(&instance->bulk_waiter_list_mutex);
-+ vchiq_log_info(vchiq_arm_log_level,
-+ "saved bulk_waiter %x for pid %d",
-+ (unsigned int)waiter, current->pid);
-+ }
-+
-+ return status;
-+}
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,71 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_MEMDRV_H
-+#define VCHIQ_MEMDRV_H
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+
-+#include <linux/kernel.h>
-+#include "vchiq_if.h"
-+
-+/* ---- Constants and Types ---------------------------------------------- */
-+
-+typedef struct {
-+ void *armSharedMemVirt;
-+ dma_addr_t armSharedMemPhys;
-+ size_t armSharedMemSize;
-+
-+ void *vcSharedMemVirt;
-+ dma_addr_t vcSharedMemPhys;
-+ size_t vcSharedMemSize;
-+} VCHIQ_SHARED_MEM_INFO_T;
-+
-+/* ---- Variable Externs ------------------------------------------------- */
-+
-+/* ---- Function Prototypes ---------------------------------------------- */
-+
-+void vchiq_get_shared_mem_info(VCHIQ_SHARED_MEM_INFO_T *info);
-+
-+VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
-+
-+VCHIQ_STATUS_T vchiq_userdrv_create_instance(
-+ const VCHIQ_PLATFORM_DATA_T * platform_data);
-+
-+VCHIQ_STATUS_T vchiq_userdrv_suspend(
-+ const VCHIQ_PLATFORM_DATA_T * platform_data);
-+
-+VCHIQ_STATUS_T vchiq_userdrv_resume(
-+ const VCHIQ_PLATFORM_DATA_T * platform_data);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,58 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_PAGELIST_H
-+#define VCHIQ_PAGELIST_H
-+
-+#ifndef PAGE_SIZE
-+#define PAGE_SIZE 4096
-+#endif
-+#define CACHE_LINE_SIZE 32
-+#define PAGELIST_WRITE 0
-+#define PAGELIST_READ 1
-+#define PAGELIST_READ_WITH_FRAGMENTS 2
-+
-+typedef struct pagelist_struct {
-+ unsigned long length;
-+ unsigned short type;
-+ unsigned short offset;
-+ unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
-+ pages at consecutive addresses. */
-+} PAGELIST_T;
-+
-+typedef struct fragments_struct {
-+ char headbuf[CACHE_LINE_SIZE];
-+ char tailbuf[CACHE_LINE_SIZE];
-+} FRAGMENTS_T;
-+
-+#endif /* VCHIQ_PAGELIST_H */
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_proc.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_proc.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_proc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_proc.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,253 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+
-+#include <linux/proc_fs.h>
-+#include "vchiq_core.h"
-+#include "vchiq_arm.h"
-+
-+#if 1
-+
-+int vchiq_proc_init(void)
-+{
-+ return 0;
-+}
-+
-+void vchiq_proc_deinit(void)
-+{
-+}
-+
-+#else
-+
-+struct vchiq_proc_info {
-+ /* Global 'vc' proc entry used by all instances */
-+ struct proc_dir_entry *vc_cfg_dir;
-+
-+ /* one entry per client process */
-+ struct proc_dir_entry *clients;
-+
-+ /* log categories */
-+ struct proc_dir_entry *log_categories;
-+};
-+
-+static struct vchiq_proc_info proc_info;
-+
-+struct proc_dir_entry *vchiq_proc_top(void)
-+{
-+ BUG_ON(proc_info.vc_cfg_dir == NULL);
-+ return proc_info.vc_cfg_dir;
-+}
-+
-+/****************************************************************************
-+*
-+* log category entries
-+*
-+***************************************************************************/
-+#define PROC_WRITE_BUF_SIZE 256
-+
-+#define VCHIQ_LOG_ERROR_STR "error"
-+#define VCHIQ_LOG_WARNING_STR "warning"
-+#define VCHIQ_LOG_INFO_STR "info"
-+#define VCHIQ_LOG_TRACE_STR "trace"
-+
-+static int log_cfg_read(char *buffer,
-+ char **start,
-+ off_t off,
-+ int count,
-+ int *eof,
-+ void *data)
-+{
-+ int len = 0;
-+ char *log_value = NULL;
-+
-+ switch (*((int *)data)) {
-+ case VCHIQ_LOG_ERROR:
-+ log_value = VCHIQ_LOG_ERROR_STR;
-+ break;
-+ case VCHIQ_LOG_WARNING:
-+ log_value = VCHIQ_LOG_WARNING_STR;
-+ break;
-+ case VCHIQ_LOG_INFO:
-+ log_value = VCHIQ_LOG_INFO_STR;
-+ break;
-+ case VCHIQ_LOG_TRACE:
-+ log_value = VCHIQ_LOG_TRACE_STR;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ len += sprintf(buffer + len,
-+ "%s\n",
-+ log_value ? log_value : "(null)");
-+
-+ return len;
-+}
-+
-+
-+static int log_cfg_write(struct file *file,
-+ const char __user *buffer,
-+ unsigned long count,
-+ void *data)
-+{
-+ int *log_module = data;
-+ char kbuf[PROC_WRITE_BUF_SIZE + 1];
-+
-+ (void)file;
-+
-+ memset(kbuf, 0, PROC_WRITE_BUF_SIZE + 1);
-+ if (count >= PROC_WRITE_BUF_SIZE)
-+ count = PROC_WRITE_BUF_SIZE;
-+
-+ if (copy_from_user(kbuf,
-+ buffer,
-+ count) != 0)
-+ return -EFAULT;
-+ kbuf[count - 1] = 0;
-+
-+ if (strncmp("error", kbuf, strlen("error")) == 0)
-+ *log_module = VCHIQ_LOG_ERROR;
-+ else if (strncmp("warning", kbuf, strlen("warning")) == 0)
-+ *log_module = VCHIQ_LOG_WARNING;
-+ else if (strncmp("info", kbuf, strlen("info")) == 0)
-+ *log_module = VCHIQ_LOG_INFO;
-+ else if (strncmp("trace", kbuf, strlen("trace")) == 0)
-+ *log_module = VCHIQ_LOG_TRACE;
-+ else
-+ *log_module = VCHIQ_LOG_DEFAULT;
-+
-+ return count;
-+}
-+
-+/* Log category proc entries */
-+struct vchiq_proc_log_entry {
-+ const char *name;
-+ int *plevel;
-+ struct proc_dir_entry *dir;
-+};
-+
-+static struct vchiq_proc_log_entry vchiq_proc_log_entries[] = {
-+ { "core", &vchiq_core_log_level },
-+ { "msg", &vchiq_core_msg_log_level },
-+ { "sync", &vchiq_sync_log_level },
-+ { "susp", &vchiq_susp_log_level },
-+ { "arm", &vchiq_arm_log_level },
-+};
-+static int n_log_entries =
-+ sizeof(vchiq_proc_log_entries)/sizeof(vchiq_proc_log_entries[0]);
-+
-+/* create an entry under /proc/vc/log for each log category */
-+static int vchiq_proc_create_log_entries(struct proc_dir_entry *top)
-+{
-+ struct proc_dir_entry *dir;
-+ size_t i;
-+ int ret = 0;
-+ dir = proc_mkdir("log", proc_info.vc_cfg_dir);
-+ if (!dir)
-+ return -ENOMEM;
-+ proc_info.log_categories = dir;
-+
-+ for (i = 0; i < n_log_entries; i++) {
-+ dir = create_proc_entry(vchiq_proc_log_entries[i].name,
-+ 0644,
-+ proc_info.log_categories);
-+ if (!dir) {
-+ ret = -ENOMEM;
-+ break;
-+ }
-+
-+ dir->read_proc = &log_cfg_read;
-+ dir->write_proc = &log_cfg_write;
-+ dir->data = (void *)vchiq_proc_log_entries[i].plevel;
-+
-+ vchiq_proc_log_entries[i].dir = dir;
-+ }
-+ return ret;
-+}
-+
-+
-+int vchiq_proc_init(void)
-+{
-+ BUG_ON(proc_info.vc_cfg_dir != NULL);
-+
-+ proc_info.vc_cfg_dir = proc_mkdir("vc", NULL);
-+ if (proc_info.vc_cfg_dir == NULL)
-+ goto fail;
-+
-+ proc_info.clients = proc_mkdir("clients",
-+ proc_info.vc_cfg_dir);
-+ if (!proc_info.clients)
-+ goto fail;
-+
-+ if (vchiq_proc_create_log_entries(proc_info.vc_cfg_dir) != 0)
-+ goto fail;
-+
-+ return 0;
-+
-+fail:
-+ vchiq_proc_deinit();
-+ vchiq_log_error(vchiq_arm_log_level,
-+ "%s: failed to create proc directory",
-+ __func__);
-+
-+ return -ENOMEM;
-+}
-+
-+/* remove all the proc entries */
-+void vchiq_proc_deinit(void)
-+{
-+ /* log category entries */
-+ if (proc_info.log_categories) {
-+ size_t i;
-+ for (i = 0; i < n_log_entries; i++)
-+ if (vchiq_proc_log_entries[i].dir)
-+ remove_proc_entry(
-+ vchiq_proc_log_entries[i].name,
-+ proc_info.log_categories);
-+
-+ remove_proc_entry(proc_info.log_categories->name,
-+ proc_info.vc_cfg_dir);
-+ }
-+ if (proc_info.clients)
-+ remove_proc_entry(proc_info.clients->name,
-+ proc_info.vc_cfg_dir);
-+ if (proc_info.vc_cfg_dir)
-+ remove_proc_entry(proc_info.vc_cfg_dir->name, NULL);
-+}
-+
-+struct proc_dir_entry *vchiq_clients_top(void)
-+{
-+ return proc_info.clients;
-+}
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,815 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+#include <linux/module.h>
-+#include <linux/types.h>
-+
-+#include "interface/vchi/vchi.h"
-+#include "vchiq.h"
-+#include "vchiq_core.h"
-+
-+#include "vchiq_util.h"
-+
-+#include <stddef.h>
-+
-+#define vchiq_status_to_vchi(status) ((int32_t)status)
-+
-+typedef struct {
-+ VCHIQ_SERVICE_HANDLE_T handle;
-+
-+ VCHIU_QUEUE_T queue;
-+
-+ VCHI_CALLBACK_T callback;
-+ void *callback_param;
-+} SHIM_SERVICE_T;
-+
-+/* ----------------------------------------------------------------------
-+ * return pointer to the mphi message driver function table
-+ * -------------------------------------------------------------------- */
-+const VCHI_MESSAGE_DRIVER_T *
-+vchi_mphi_message_driver_func_table(void)
-+{
-+ return NULL;
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * return a pointer to the 'single' connection driver fops
-+ * -------------------------------------------------------------------- */
-+const VCHI_CONNECTION_API_T *
-+single_get_func_table(void)
-+{
-+ return NULL;
-+}
-+
-+VCHI_CONNECTION_T *vchi_create_connection(
-+ const VCHI_CONNECTION_API_T *function_table,
-+ const VCHI_MESSAGE_DRIVER_T *low_level)
-+{
-+ (void)function_table;
-+ (void)low_level;
-+ return NULL;
-+}
-+
-+/***********************************************************
-+ * Name: vchi_msg_peek
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle,
-+ * void **data,
-+ * uint32_t *msg_size,
-+
-+
-+ * VCHI_FLAGS_T flags
-+ *
-+ * Description: Routine to return a pointer to the current message (to allow in
-+ * place processing). The message can be removed using
-+ * vchi_msg_remove when you're finished
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ WARN_ON((flags != VCHI_FLAGS_NONE) &&
-+ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
-+
-+ if (flags == VCHI_FLAGS_NONE)
-+ if (vchiu_queue_is_empty(&service->queue))
-+ return -1;
-+
-+ header = vchiu_queue_peek(&service->queue);
-+
-+ *data = header->data;
-+ *msg_size = header->size;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_peek);
-+
-+/***********************************************************
-+ * Name: vchi_msg_remove
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle,
-+ *
-+ * Description: Routine to remove a message (after it has been read with
-+ * vchi_msg_peek)
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ header = vchiu_queue_pop(&service->queue);
-+
-+ vchiq_release_message(service->handle, header);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_remove);
-+
-+/***********************************************************
-+ * Name: vchi_msg_queue
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * const void *data,
-+ * uint32_t data_size,
-+ * VCHI_FLAGS_T flags,
-+ * void *msg_handle,
-+ *
-+ * Description: Thin wrapper to queue a message onto a connection
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
-+ const void *data,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_ELEMENT_T element = {data, data_size};
-+ VCHIQ_STATUS_T status;
-+
-+ (void)msg_handle;
-+
-+ WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
-+
-+ status = vchiq_queue_message(service->handle, &element, 1);
-+
-+ /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
-+ ** implement a retry mechanism since this function is supposed
-+ ** to block until queued
-+ */
-+ while (status == VCHIQ_RETRY) {
-+ msleep(1);
-+ status = vchiq_queue_message(service->handle, &element, 1);
-+ }
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_msg_queue);
-+
-+/***********************************************************
-+ * Name: vchi_bulk_queue_receive
-+ *
-+ * Arguments: VCHI_BULK_HANDLE_T handle,
-+ * void *data_dst,
-+ * const uint32_t data_size,
-+ * VCHI_FLAGS_T flags
-+ * void *bulk_handle
-+ *
-+ * Description: Routine to setup a rcv buffer
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
-+ void *data_dst,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_BULK_MODE_T mode;
-+ VCHIQ_STATUS_T status;
-+
-+ switch ((int)flags) {
-+ case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
-+ | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ WARN_ON(!service->callback);
-+ mode = VCHIQ_BULK_MODE_CALLBACK;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
-+ mode = VCHIQ_BULK_MODE_BLOCKING;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ case VCHI_FLAGS_NONE:
-+ mode = VCHIQ_BULK_MODE_NOCALLBACK;
-+ break;
-+ default:
-+ WARN(1, "unsupported message\n");
-+ return vchiq_status_to_vchi(VCHIQ_ERROR);
-+ }
-+
-+ status = vchiq_bulk_receive(service->handle, data_dst, data_size,
-+ bulk_handle, mode);
-+
-+ /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
-+ ** implement a retry mechanism since this function is supposed
-+ ** to block until queued
-+ */
-+ while (status == VCHIQ_RETRY) {
-+ msleep(1);
-+ status = vchiq_bulk_receive(service->handle, data_dst,
-+ data_size, bulk_handle, mode);
-+ }
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_bulk_queue_receive);
-+
-+/***********************************************************
-+ * Name: vchi_bulk_queue_transmit
-+ *
-+ * Arguments: VCHI_BULK_HANDLE_T handle,
-+ * const void *data_src,
-+ * uint32_t data_size,
-+ * VCHI_FLAGS_T flags,
-+ * void *bulk_handle
-+ *
-+ * Description: Routine to transmit some data
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
-+ const void *data_src,
-+ uint32_t data_size,
-+ VCHI_FLAGS_T flags,
-+ void *bulk_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_BULK_MODE_T mode;
-+ VCHIQ_STATUS_T status;
-+
-+ switch ((int)flags) {
-+ case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
-+ | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ WARN_ON(!service->callback);
-+ mode = VCHIQ_BULK_MODE_CALLBACK;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
-+ case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
-+ mode = VCHIQ_BULK_MODE_BLOCKING;
-+ break;
-+ case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
-+ case VCHI_FLAGS_NONE:
-+ mode = VCHIQ_BULK_MODE_NOCALLBACK;
-+ break;
-+ default:
-+ WARN(1, "unsupported message\n");
-+ return vchiq_status_to_vchi(VCHIQ_ERROR);
-+ }
-+
-+ status = vchiq_bulk_transmit(service->handle, data_src, data_size,
-+ bulk_handle, mode);
-+
-+ /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
-+ ** implement a retry mechanism since this function is supposed
-+ ** to block until queued
-+ */
-+ while (status == VCHIQ_RETRY) {
-+ msleep(1);
-+ status = vchiq_bulk_transmit(service->handle, data_src,
-+ data_size, bulk_handle, mode);
-+ }
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_bulk_queue_transmit);
-+
-+/***********************************************************
-+ * Name: vchi_msg_dequeue
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * void *data,
-+ * uint32_t max_data_size_to_read,
-+ * uint32_t *actual_msg_size
-+ * VCHI_FLAGS_T flags
-+ *
-+ * Description: Routine to dequeue a message into the supplied buffer
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
-+ void *data,
-+ uint32_t max_data_size_to_read,
-+ uint32_t *actual_msg_size,
-+ VCHI_FLAGS_T flags)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ WARN_ON((flags != VCHI_FLAGS_NONE) &&
-+ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
-+
-+ if (flags == VCHI_FLAGS_NONE)
-+ if (vchiu_queue_is_empty(&service->queue))
-+ return -1;
-+
-+ header = vchiu_queue_pop(&service->queue);
-+
-+ memcpy(data, header->data, header->size < max_data_size_to_read ?
-+ header->size : max_data_size_to_read);
-+
-+ *actual_msg_size = header->size;
-+
-+ vchiq_release_message(service->handle, header);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(vchi_msg_dequeue);
-+
-+/***********************************************************
-+ * Name: vchi_msg_queuev
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * VCHI_MSG_VECTOR_T *vector,
-+ * uint32_t count,
-+ * VCHI_FLAGS_T flags,
-+ * void *msg_handle
-+ *
-+ * Description: Thin wrapper to queue a message onto a connection
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+
-+vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
-+vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
-+ offsetof(VCHIQ_ELEMENT_T, data));
-+vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
-+ offsetof(VCHIQ_ELEMENT_T, size));
-+
-+int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
-+ VCHI_MSG_VECTOR_T *vector,
-+ uint32_t count,
-+ VCHI_FLAGS_T flags,
-+ void *msg_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+
-+ (void)msg_handle;
-+
-+ WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
-+
-+ return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
-+ (const VCHIQ_ELEMENT_T *)vector, count));
-+}
-+EXPORT_SYMBOL(vchi_msg_queuev);
-+
-+/***********************************************************
-+ * Name: vchi_held_msg_release
-+ *
-+ * Arguments: VCHI_HELD_MSG_T *message
-+ *
-+ * Description: Routine to release a held message (after it has been read with
-+ * vchi_msg_hold)
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
-+{
-+ vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
-+ (VCHIQ_HEADER_T *)message->message);
-+
-+ return 0;
-+}
-+
-+/***********************************************************
-+ * Name: vchi_msg_hold
-+ *
-+ * Arguments: VCHI_SERVICE_HANDLE_T handle,
-+ * void **data,
-+ * uint32_t *msg_size,
-+ * VCHI_FLAGS_T flags,
-+ * VCHI_HELD_MSG_T *message_handle
-+ *
-+ * Description: Routine to return a pointer to the current message (to allow
-+ * in place processing). The message is dequeued - don't forget
-+ * to release the message using vchi_held_msg_release when you're
-+ * finished.
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
-+ void **data,
-+ uint32_t *msg_size,
-+ VCHI_FLAGS_T flags,
-+ VCHI_HELD_MSG_T *message_handle)
-+{
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ VCHIQ_HEADER_T *header;
-+
-+ WARN_ON((flags != VCHI_FLAGS_NONE) &&
-+ (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
-+
-+ if (flags == VCHI_FLAGS_NONE)
-+ if (vchiu_queue_is_empty(&service->queue))
-+ return -1;
-+
-+ header = vchiu_queue_pop(&service->queue);
-+
-+ *data = header->data;
-+ *msg_size = header->size;
-+
-+ message_handle->service =
-+ (struct opaque_vchi_service_t *)service->handle;
-+ message_handle->message = header;
-+
-+ return 0;
-+}
-+
-+/***********************************************************
-+ * Name: vchi_initialise
-+ *
-+ * Arguments: VCHI_INSTANCE_T *instance_handle
-+ * VCHI_CONNECTION_T **connections
-+ * const uint32_t num_connections
-+ *
-+ * Description: Initialises the hardware but does not transmit anything
-+ * When run as a Host App this will be called twice hence the need
-+ * to malloc the state information
-+ *
-+ * Returns: 0 if successful, failure otherwise
-+ *
-+ ***********************************************************/
-+
-+int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
-+{
-+ VCHIQ_INSTANCE_T instance;
-+ VCHIQ_STATUS_T status;
-+
-+ status = vchiq_initialise(&instance);
-+
-+ *instance_handle = (VCHI_INSTANCE_T)instance;
-+
-+ return vchiq_status_to_vchi(status);
-+}
-+EXPORT_SYMBOL(vchi_initialise);
-+
-+/***********************************************************
-+ * Name: vchi_connect
-+ *
-+ * Arguments: VCHI_CONNECTION_T **connections
-+ * const uint32_t num_connections
-+ * VCHI_INSTANCE_T instance_handle)
-+ *
-+ * Description: Starts the command service on each connection,
-+ * causing INIT messages to be pinged back and forth
-+ *
-+ * Returns: 0 if successful, failure otherwise
-+ *
-+ ***********************************************************/
-+int32_t vchi_connect(VCHI_CONNECTION_T **connections,
-+ const uint32_t num_connections,
-+ VCHI_INSTANCE_T instance_handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+
-+ (void)connections;
-+ (void)num_connections;
-+
-+ return vchiq_connect(instance);
-+}
-+EXPORT_SYMBOL(vchi_connect);
-+
-+
-+/***********************************************************
-+ * Name: vchi_disconnect
-+ *
-+ * Arguments: VCHI_INSTANCE_T instance_handle
-+ *
-+ * Description: Stops the command service on each connection,
-+ * causing DE-INIT messages to be pinged back and forth
-+ *
-+ * Returns: 0 if successful, failure otherwise
-+ *
-+ ***********************************************************/
-+int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+ return vchiq_status_to_vchi(vchiq_shutdown(instance));
-+}
-+EXPORT_SYMBOL(vchi_disconnect);
-+
-+
-+/***********************************************************
-+ * Name: vchi_service_open
-+ * Name: vchi_service_create
-+ *
-+ * Arguments: VCHI_INSTANCE_T *instance_handle
-+ * SERVICE_CREATION_T *setup,
-+ * VCHI_SERVICE_HANDLE_T *handle
-+ *
-+ * Description: Routine to open a service
-+ *
-+ * Returns: int32_t - success == 0
-+ *
-+ ***********************************************************/
-+
-+static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
-+ VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
-+{
-+ SHIM_SERVICE_T *service =
-+ (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
-+
-+ switch (reason) {
-+ case VCHIQ_MESSAGE_AVAILABLE:
-+ vchiu_queue_push(&service->queue, header);
-+
-+ if (service->callback)
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_MSG_AVAILABLE, NULL);
-+ break;
-+ case VCHIQ_BULK_TRANSMIT_DONE:
-+ if (service->callback)
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_SENT, bulk_user);
-+ break;
-+ case VCHIQ_BULK_RECEIVE_DONE:
-+ if (service->callback)
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
-+ break;
-+ case VCHIQ_SERVICE_CLOSED:
-+ if (service->callback)
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_SERVICE_CLOSED, NULL);
-+ break;
-+ case VCHIQ_SERVICE_OPENED:
-+ /* No equivalent VCHI reason */
-+ break;
-+ case VCHIQ_BULK_TRANSMIT_ABORTED:
-+ if (service->callback)
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, bulk_user);
-+ break;
-+ case VCHIQ_BULK_RECEIVE_ABORTED:
-+ if (service->callback)
-+ service->callback(service->callback_param,
-+ VCHI_CALLBACK_BULK_RECEIVE_ABORTED, bulk_user);
-+ break;
-+ default:
-+ WARN(1, "not supported\n");
-+ break;
-+ }
-+
-+ return VCHIQ_SUCCESS;
-+}
-+
-+static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
-+ SERVICE_CREATION_T *setup)
-+{
-+ SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
-+
-+ (void)instance;
-+
-+ if (service) {
-+ if (vchiu_queue_init(&service->queue, 64)) {
-+ service->callback = setup->callback;
-+ service->callback_param = setup->callback_param;
-+ } else {
-+ kfree(service);
-+ service = NULL;
-+ }
-+ }
-+
-+ return service;
-+}
-+
-+static void service_free(SHIM_SERVICE_T *service)
-+{
-+ if (service) {
-+ vchiu_queue_delete(&service->queue);
-+ kfree(service);
-+ }
-+}
-+
-+int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+ SHIM_SERVICE_T *service = service_alloc(instance, setup);
-+ if (service) {
-+ VCHIQ_SERVICE_PARAMS_T params;
-+ VCHIQ_STATUS_T status;
-+
-+ memset(&params, 0, sizeof(params));
-+ params.fourcc = setup->service_id;
-+ params.callback = shim_callback;
-+ params.userdata = service;
-+ params.version = setup->version.version;
-+ params.version_min = setup->version.version_min;
-+
-+ status = vchiq_open_service(instance, &params,
-+ &service->handle);
-+ if (status != VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ }
-+ }
-+
-+ *handle = (VCHI_SERVICE_HANDLE_T)service;
-+
-+ return (service != NULL) ? 0 : -1;
-+}
-+EXPORT_SYMBOL(vchi_service_open);
-+
-+int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
-+ SERVICE_CREATION_T *setup,
-+ VCHI_SERVICE_HANDLE_T *handle)
-+{
-+ VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
-+ SHIM_SERVICE_T *service = service_alloc(instance, setup);
-+ if (service) {
-+ VCHIQ_SERVICE_PARAMS_T params;
-+ VCHIQ_STATUS_T status;
-+
-+ memset(&params, 0, sizeof(params));
-+ params.fourcc = setup->service_id;
-+ params.callback = shim_callback;
-+ params.userdata = service;
-+ params.version = setup->version.version;
-+ params.version_min = setup->version.version_min;
-+ status = vchiq_add_service(instance, &params, &service->handle);
-+
-+ if (status != VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ }
-+ }
-+
-+ *handle = (VCHI_SERVICE_HANDLE_T)service;
-+
-+ return (service != NULL) ? 0 : -1;
-+}
-+EXPORT_SYMBOL(vchi_service_create);
-+
-+int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service) {
-+ VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
-+ if (status == VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ }
-+
-+ ret = vchiq_status_to_vchi(status);
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_close);
-+
-+int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service) {
-+ VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
-+ if (status == VCHIQ_SUCCESS) {
-+ service_free(service);
-+ service = NULL;
-+ }
-+
-+ ret = vchiq_status_to_vchi(status);
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_destroy);
-+
-+int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if(service)
-+ {
-+ VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
-+ ret = vchiq_status_to_vchi( status );
-+ }
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_get_peer_version);
-+
-+/* ----------------------------------------------------------------------
-+ * read a uint32_t from buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+uint32_t
-+vchi_readbuf_uint32(const void *_ptr)
-+{
-+ const unsigned char *ptr = _ptr;
-+ return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * write a uint32_t to buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+void
-+vchi_writebuf_uint32(void *_ptr, uint32_t value)
-+{
-+ unsigned char *ptr = _ptr;
-+ ptr[0] = (unsigned char)((value >> 0) & 0xFF);
-+ ptr[1] = (unsigned char)((value >> 8) & 0xFF);
-+ ptr[2] = (unsigned char)((value >> 16) & 0xFF);
-+ ptr[3] = (unsigned char)((value >> 24) & 0xFF);
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * read a uint16_t from buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+uint16_t
-+vchi_readbuf_uint16(const void *_ptr)
-+{
-+ const unsigned char *ptr = _ptr;
-+ return ptr[0] | (ptr[1] << 8);
-+}
-+
-+/* ----------------------------------------------------------------------
-+ * write a uint16_t into the buffer.
-+ * network format is defined to be little endian
-+ * -------------------------------------------------------------------- */
-+void
-+vchi_writebuf_uint16(void *_ptr, uint16_t value)
-+{
-+ unsigned char *ptr = _ptr;
-+ ptr[0] = (value >> 0) & 0xFF;
-+ ptr[1] = (value >> 8) & 0xFF;
-+}
-+
-+/***********************************************************
-+ * Name: vchi_service_use
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
-+ *
-+ * Description: Routine to increment refcount on a service
-+ *
-+ * Returns: void
-+ *
-+ ***********************************************************/
-+int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service)
-+ ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_use);
-+
-+/***********************************************************
-+ * Name: vchi_service_release
-+ *
-+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
-+ *
-+ * Description: Routine to decrement refcount on a service
-+ *
-+ * Returns: void
-+ *
-+ ***********************************************************/
-+int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
-+{
-+ int32_t ret = -1;
-+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
-+ if (service)
-+ ret = vchiq_status_to_vchi(
-+ vchiq_release_service(service->handle));
-+ return ret;
-+}
-+EXPORT_SYMBOL(vchi_service_release);
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,151 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include "vchiq_util.h"
-+
-+static inline int is_pow2(int i)
-+{
-+ return i && !(i & (i - 1));
-+}
-+
-+int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
-+{
-+ WARN_ON(!is_pow2(size));
-+
-+ queue->size = size;
-+ queue->read = 0;
-+ queue->write = 0;
-+
-+ sema_init(&queue->pop, 0);
-+ sema_init(&queue->push, 0);
-+
-+ queue->storage = kzalloc(size * sizeof(VCHIQ_HEADER_T *), GFP_KERNEL);
-+ if (queue->storage == NULL) {
-+ vchiu_queue_delete(queue);
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
-+{
-+ if (queue->storage != NULL)
-+ kfree(queue->storage);
-+}
-+
-+int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
-+{
-+ return queue->read == queue->write;
-+}
-+
-+int vchiu_queue_is_full(VCHIU_QUEUE_T *queue)
-+{
-+ return queue->write == queue->read + queue->size;
-+}
-+
-+void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
-+{
-+ while (queue->write == queue->read + queue->size) {
-+ if (down_interruptible(&queue->pop) != 0) {
-+ flush_signals(current);
-+ }
-+ }
-+
-+ /*
-+ * Write to queue->storage must be visible after read from
-+ * queue->read
-+ */
-+ smp_mb();
-+
-+ queue->storage[queue->write & (queue->size - 1)] = header;
-+
-+ /*
-+ * Write to queue->storage must be visible before write to
-+ * queue->write
-+ */
-+ smp_wmb();
-+
-+ queue->write++;
-+
-+ up(&queue->push);
-+}
-+
-+VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
-+{
-+ while (queue->write == queue->read) {
-+ if (down_interruptible(&queue->push) != 0) {
-+ flush_signals(current);
-+ }
-+ }
-+
-+ up(&queue->push); // We haven't removed anything from the queue.
-+
-+ /*
-+ * Read from queue->storage must be visible after read from
-+ * queue->write
-+ */
-+ smp_rmb();
-+
-+ return queue->storage[queue->read & (queue->size - 1)];
-+}
-+
-+VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
-+{
-+ VCHIQ_HEADER_T *header;
-+
-+ while (queue->write == queue->read) {
-+ if (down_interruptible(&queue->push) != 0) {
-+ flush_signals(current);
-+ }
-+ }
-+
-+ /*
-+ * Read from queue->storage must be visible after read from
-+ * queue->write
-+ */
-+ smp_rmb();
-+
-+ header = queue->storage[queue->read & (queue->size - 1)];
-+
-+ /*
-+ * Read from queue->storage must be visible before write to
-+ * queue->read
-+ */
-+ smp_mb();
-+
-+ queue->read++;
-+
-+ up(&queue->pop);
-+
-+ return header;
-+}
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,81 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#ifndef VCHIQ_UTIL_H
-+#define VCHIQ_UTIL_H
-+
-+#include <linux/types.h>
-+#include <linux/semaphore.h>
-+#include <linux/mutex.h>
-+#include <linux/bitops.h>
-+#include <linux/kthread.h>
-+#include <linux/wait.h>
-+#include <linux/vmalloc.h>
-+#include <linux/jiffies.h>
-+#include <linux/delay.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/interrupt.h>
-+#include <linux/random.h>
-+#include <linux/sched.h>
-+#include <linux/ctype.h>
-+#include <linux/uaccess.h>
-+#include <linux/time.h> /* for time_t */
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+
-+#include "vchiq_if.h"
-+
-+typedef struct {
-+ int size;
-+ int read;
-+ int write;
-+
-+ struct semaphore pop;
-+ struct semaphore push;
-+
-+ VCHIQ_HEADER_T **storage;
-+} VCHIU_QUEUE_T;
-+
-+extern int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
-+extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
-+
-+extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
-+extern int vchiu_queue_is_full(VCHIU_QUEUE_T *queue);
-+
-+extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
-+
-+extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
-+extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c
---- linux-3.11.10.orig/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,59 @@
-+/**
-+ * Copyright (c) 2010-2012 Broadcom. 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+#include "vchiq_build_info.h"
-+#include <linux/broadcom/vc_debug_sym.h>
-+
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_hostname, "dc4-arm-01" );
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_version, "9245b4c35b99b3870e1f7dc598c5692b3c66a6f0 (tainted)" );
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_time, __TIME__ );
-+VC_DEBUG_DECLARE_STRING_VAR( vchiq_build_date, __DATE__ );
-+
-+const char *vchiq_get_build_hostname( void )
-+{
-+ return vchiq_build_hostname;
-+}
-+
-+const char *vchiq_get_build_version( void )
-+{
-+ return vchiq_build_version;
-+}
-+
-+const char *vchiq_get_build_date( void )
-+{
-+ return vchiq_build_date;
-+}
-+
-+const char *vchiq_get_build_time( void )
-+{
-+ return vchiq_build_time;
-+}
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/Kconfig linux-3.11.10/drivers/misc/vc04_services/Kconfig
---- linux-3.11.10.orig/drivers/misc/vc04_services/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,9 @@
-+config BCM2708_VCHIQ
-+ tristate "Videocore VCHIQ"
-+ depends on MACH_BCM2708
-+ default y
-+ help
-+ Kernel to VideoCore communication interface for the
-+ BCM2708 family of products.
-+ Defaults to Y when the Broadcom Videocore services
-+ are included in the build, N otherwise.
-diff -Nur linux-3.11.10.orig/drivers/misc/vc04_services/Makefile linux-3.11.10/drivers/misc/vc04_services/Makefile
---- linux-3.11.10.orig/drivers/misc/vc04_services/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/misc/vc04_services/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,17 @@
-+ifeq ($(CONFIG_MACH_BCM2708),y)
-+
-+obj-$(CONFIG_BCM2708_VCHIQ) += vchiq.o
-+
-+vchiq-objs := \
-+ interface/vchiq_arm/vchiq_core.o \
-+ interface/vchiq_arm/vchiq_arm.o \
-+ interface/vchiq_arm/vchiq_kern_lib.o \
-+ interface/vchiq_arm/vchiq_2835_arm.o \
-+ interface/vchiq_arm/vchiq_proc.o \
-+ interface/vchiq_arm/vchiq_shim.o \
-+ interface/vchiq_arm/vchiq_util.o \
-+ interface/vchiq_arm/vchiq_connected.o \
-+
-+EXTRA_CFLAGS += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000
-+
-+endif
-diff -Nur linux-3.11.10.orig/drivers/mmc/card/block.c linux-3.11.10/drivers/mmc/card/block.c
---- linux-3.11.10.orig/drivers/mmc/card/block.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/card/block.c 2014-02-07 19:57:28.000000000 +0100
-@@ -1322,7 +1322,7 @@
- brq->data.blocks = 1;
- }
-
-- if (brq->data.blocks > 1 || do_rel_wr) {
-+ if (brq->data.blocks > 1 || do_rel_wr || card->host->caps2 & MMC_CAP2_FORCE_MULTIBLOCK) {
- /* SPI multiblock writes terminate using a special
- * token, not a STOP_TRANSMISSION request.
- */
-diff -Nur linux-3.11.10.orig/drivers/mmc/core/sd.c linux-3.11.10/drivers/mmc/core/sd.c
---- linux-3.11.10.orig/drivers/mmc/core/sd.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/core/sd.c 2014-02-07 19:57:28.000000000 +0100
-@@ -13,6 +13,8 @@
- #include <linux/err.h>
- #include <linux/slab.h>
- #include <linux/stat.h>
-+#include <linux/jiffies.h>
-+#include <linux/nmi.h>
-
- #include <linux/mmc/host.h>
- #include <linux/mmc/card.h>
-@@ -58,6 +60,15 @@
- __res & __mask; \
- })
-
-+// timeout for tries
-+static const unsigned long retry_timeout_ms= 10*1000;
-+
-+// try at least 10 times, even if timeout is reached
-+static const int retry_min_tries= 10;
-+
-+// delay between tries
-+static const unsigned long retry_delay_ms= 10;
-+
- /*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-@@ -210,12 +221,62 @@
- }
-
- /*
-- * Fetch and process SD Status register.
-+ * Fetch and process SD Configuration Register.
-+ */
-+static int mmc_read_scr(struct mmc_card *card)
-+{
-+ unsigned long timeout_at;
-+ int err, tries;
-+
-+ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms );
-+ tries= 0;
-+
-+ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) )
-+ {
-+ unsigned long delay_at;
-+ tries++;
-+
-+ err = mmc_app_send_scr(card, card->raw_scr);
-+ if( !err )
-+ break; // success!!!
-+
-+ touch_nmi_watchdog(); // we are still alive!
-+
-+ // delay
-+ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms );
-+ while( time_before( jiffies, delay_at ) )
-+ {
-+ mdelay( 1 );
-+ touch_nmi_watchdog(); // we are still alive!
-+ }
-+ }
-+
-+ if( err)
-+ {
-+ pr_err("%s: failed to read SD Configuration register (SCR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err );
-+ return err;
-+ }
-+
-+ if( tries > 1 )
-+ {
-+ pr_info("%s: could read SD Configuration register (SCR) at the %dth attempt\n", mmc_hostname(card->host), tries );
-+ }
-+
-+ err = mmc_decode_scr(card);
-+ if (err)
-+ return err;
-+
-+ return err;
-+}
-+
-+/*
-+ * Fetch and process SD Status Register.
- */
- static int mmc_read_ssr(struct mmc_card *card)
- {
-+ unsigned long timeout_at;
- unsigned int au, es, et, eo;
-- int err, i;
-+ int err, i, tries;
- u32 *ssr;
-
- if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
-@@ -228,14 +289,40 @@
- if (!ssr)
- return -ENOMEM;
-
-- err = mmc_app_sd_status(card, ssr);
-- if (err) {
-- pr_warning("%s: problem reading SD Status "
-- "register.\n", mmc_hostname(card->host));
-- err = 0;
-+ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms );
-+ tries= 0;
-+
-+ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) )
-+ {
-+ unsigned long delay_at;
-+ tries++;
-+
-+ err= mmc_app_sd_status(card, ssr);
-+ if( !err )
-+ break; // sucess!!!
-+
-+ touch_nmi_watchdog(); // we are still alive!
-+
-+ // delay
-+ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms );
-+ while( time_before( jiffies, delay_at ) )
-+ {
-+ mdelay( 1 );
-+ touch_nmi_watchdog(); // we are still alive!
-+ }
-+ }
-+
-+ if( err)
-+ {
-+ pr_err("%s: failed to read SD Status register (SSR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err );
- goto out;
- }
-
-+ if( tries > 1 )
-+ {
-+ pr_info("%s: read SD Status register (SSR) after %d attempts\n", mmc_hostname(card->host), tries );
-+ }
-+
- for (i = 0; i < 16; i++)
- ssr[i] = be32_to_cpu(ssr[i]);
-
-@@ -813,14 +900,10 @@
-
- if (!reinit) {
- /*
-- * Fetch SCR from card.
-+ * Fetch and decode SD Configuration register.
- */
-- err = mmc_app_send_scr(card, card->raw_scr);
-- if (err)
-- return err;
--
-- err = mmc_decode_scr(card);
-- if (err)
-+ err = mmc_read_scr(card);
-+ if( err )
- return err;
-
- /*
-diff -Nur linux-3.11.10.orig/drivers/mmc/host/Kconfig linux-3.11.10/drivers/mmc/host/Kconfig
---- linux-3.11.10.orig/drivers/mmc/host/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/host/Kconfig 2014-02-07 19:57:28.000000000 +0100
-@@ -260,6 +260,27 @@
-
- If you have a controller with this interface, say Y or M here.
-
-+config MMC_SDHCI_BCM2708
-+ tristate "SDHCI support on BCM2708"
-+ depends on MMC_SDHCI && MACH_BCM2708
-+ select MMC_SDHCI_IO_ACCESSORS
-+ help
-+ This selects the Secure Digital Host Controller Interface (SDHCI)
-+ often referrered to as the eMMC block.
-+
-+ If you have a controller with this interface, say Y or M here.
-+
-+ If unsure, say N.
-+
-+config MMC_SDHCI_BCM2708_DMA
-+ bool "DMA support on BCM2708 Arasan controller"
-+ depends on MMC_SDHCI_BCM2708
-+ help
-+ Enable DMA support on the Arasan SDHCI controller in Broadcom 2708
-+ based chips.
-+
-+ If unsure, say N.
-+
- config MMC_SDHCI_BCM2835
- tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
- depends on ARCH_BCM2835
-diff -Nur linux-3.11.10.orig/drivers/mmc/host/Makefile linux-3.11.10/drivers/mmc/host/Makefile
---- linux-3.11.10.orig/drivers/mmc/host/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/host/Makefile 2014-02-07 19:57:28.000000000 +0100
-@@ -15,6 +15,7 @@
- obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
- obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
- obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
-+obj-$(CONFIG_MMC_SDHCI_BCM2708) += sdhci-bcm2708.o
- obj-$(CONFIG_MMC_WBSD) += wbsd.o
- obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
- obj-$(CONFIG_MMC_OMAP) += omap.o
-diff -Nur linux-3.11.10.orig/drivers/mmc/host/sdhci-bcm2708.c linux-3.11.10/drivers/mmc/host/sdhci-bcm2708.c
---- linux-3.11.10.orig/drivers/mmc/host/sdhci-bcm2708.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/host/sdhci-bcm2708.c 2014-02-07 19:57:28.000000000 +0100
-@@ -0,0 +1,1420 @@
-+/*
-+ * sdhci-bcm2708.c Support for SDHCI device on BCM2708
-+ * Copyright (c) 2010 Broadcom
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+/* Supports:
-+ * SDHCI platform device - Arasan SD controller in BCM2708
-+ *
-+ * Inspired by sdhci-pci.c, by Pierre Ossman
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/highmem.h>
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/mmc/mmc.h>
-+#include <linux/mmc/host.h>
-+#include <linux/mmc/sd.h>
-+
-+#include <linux/io.h>
-+#include <linux/dma-mapping.h>
-+#include <mach/dma.h>
-+
-+#include "sdhci.h"
-+
-+/*****************************************************************************\
-+ * *
-+ * Configuration *
-+ * *
-+\*****************************************************************************/
-+
-+#define DRIVER_NAME "bcm2708_sdhci"
-+
-+/* for the time being insist on DMA mode - PIO seems not to work */
-+#ifndef CONFIG_MMC_SDHCI_BCM2708_DMA
-+#warning Non-DMA (PIO) version of this driver currently unavailable
-+#endif
-+#undef CONFIG_MMC_SDHCI_BCM2708_DMA
-+#define CONFIG_MMC_SDHCI_BCM2708_DMA y
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+/* #define CHECK_DMA_USE */
-+#endif
-+//#define LOG_REGISTERS
-+
-+#define USE_SCHED_TIME
-+#define USE_SPACED_WRITES_2CLK 1 /* space consecutive register writes */
-+#define USE_SOFTWARE_TIMEOUTS 1 /* not hardware timeouts */
-+#define SOFTWARE_ERASE_TIMEOUT_SEC 30
-+
-+#define SDHCI_BCM_DMA_CHAN 4 /* this default is normally overriden */
-+#define SDHCI_BCM_DMA_WAITS 0 /* delays slowing DMA transfers: 0-31 */
-+/* We are worried that SD card DMA use may be blocking the AXI bus for others */
-+
-+/*! TODO: obtain these from the physical address */
-+#define DMA_SDHCI_BASE 0x7e300000 /* EMMC register block on Videocore */
-+#define DMA_SDHCI_BUFFER (DMA_SDHCI_BASE + SDHCI_BUFFER)
-+
-+#define BCM2708_SDHCI_SLEEP_TIMEOUT 1000 /* msecs */
-+
-+/* Mhz clock that the EMMC core is running at. Should match the platform clockman settings */
-+#define BCM2708_EMMC_CLOCK_FREQ 50000000
-+
-+#define REG_EXRDFIFO_EN 0x80
-+#define REG_EXRDFIFO_CFG 0x84
-+
-+int cycle_delay=2;
-+
-+/*****************************************************************************\
-+ * *
-+ * Debug *
-+ * *
-+\*****************************************************************************/
-+
-+
-+
-+#define DBG(f, x...) \
-+ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-+// printk(KERN_INFO DRIVER_NAME " [%s()]: " f, __func__,## x)//GRAYG
-+
-+
-+/*****************************************************************************\
-+ * *
-+ * High Precision Time *
-+ * *
-+\*****************************************************************************/
-+
-+#ifdef USE_SCHED_TIME
-+
-+#include <mach/frc.h>
-+
-+typedef unsigned long hptime_t;
-+
-+#define FMT_HPT "lu"
-+
-+static inline hptime_t hptime(void)
-+{
-+ return frc_clock_ticks32();
-+}
-+
-+#define HPTIME_CLK_NS 1000ul
-+
-+#else
-+
-+typedef unsigned long hptime_t;
-+
-+#define FMT_HPT "lu"
-+
-+static inline hptime_t hptime(void)
-+{
-+ return jiffies;
-+}
-+
-+#define HPTIME_CLK_NS (1000000000ul/HZ)
-+
-+#endif
-+
-+static inline unsigned long int since_ns(hptime_t t)
-+{
-+ return (unsigned long)((hptime() - t) * HPTIME_CLK_NS);
-+}
-+
-+static bool allow_highspeed = 1;
-+static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ;
-+static bool sync_after_dma = 1;
-+static bool missing_status = 1;
-+static bool spurious_crc_acmd51 = 0;
-+bool enable_llm = 1;
-+bool extra_messages = 0;
-+
-+#if 0
-+static void hptime_test(void)
-+{
-+ hptime_t now;
-+ hptime_t later;
-+
-+ now = hptime();
-+ msleep(10);
-+ later = hptime();
-+
-+ printk(KERN_INFO DRIVER_NAME": 10ms = %"FMT_HPT" clks "
-+ "(from %"FMT_HPT" to %"FMT_HPT") = %luns\n",
-+ later-now, now, later,
-+ (unsigned long)(HPTIME_CLK_NS * (later - now)));
-+
-+ now = hptime();
-+ msleep(1000);
-+ later = hptime();
-+
-+ printk(KERN_INFO DRIVER_NAME": 1s = %"FMT_HPT" clks "
-+ "(from %"FMT_HPT" to %"FMT_HPT") = %luns\n",
-+ later-now, now, later,
-+ (unsigned long)(HPTIME_CLK_NS * (later - now)));
-+}
-+#endif
-+
-+/*****************************************************************************\
-+ * *
-+ * SDHCI core callbacks *
-+ * *
-+\*****************************************************************************/
-+
-+
-+#ifdef CHECK_DMA_USE
-+/*#define CHECK_DMA_REG_USE*/
-+#endif
-+
-+#ifdef CHECK_DMA_REG_USE
-+/* we don't expect anything to be using these registers during a
-+ DMA (except the IRQ status) - so check */
-+static void check_dma_reg_use(struct sdhci_host *host, int reg);
-+#else
-+#define check_dma_reg_use(host, reg)
-+#endif
-+
-+
-+static inline u32 sdhci_bcm2708_raw_readl(struct sdhci_host *host, int reg)
-+{
-+ return readl(host->ioaddr + reg);
-+}
-+
-+u32 sdhci_bcm2708_readl(struct sdhci_host *host, int reg)
-+{
-+ u32 l = sdhci_bcm2708_raw_readl(host, reg);
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: readl from 0x%02x, value 0x%08x\n",
-+ mmc_hostname(host->mmc), reg, l);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ return l;
-+}
-+
-+u16 sdhci_bcm2708_readw(struct sdhci_host *host, int reg)
-+{
-+ u32 l = sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 w = l >> (reg << 3 & 0x18) & 0xffff;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: readw from 0x%02x, value 0x%04x\n",
-+ mmc_hostname(host->mmc), reg, w);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ return (u16)w;
-+}
-+
-+u8 sdhci_bcm2708_readb(struct sdhci_host *host, int reg)
-+{
-+ u32 l = sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 b = l >> (reg << 3 & 0x18) & 0xff;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: readb from 0x%02x, value 0x%02x\n",
-+ mmc_hostname(host->mmc), reg, b);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ return (u8)b;
-+}
-+
-+
-+static void sdhci_bcm2708_raw_writel(struct sdhci_host *host, u32 val, int reg)
-+{
-+ u32 ier;
-+
-+#if USE_SPACED_WRITES_2CLK
-+ static bool timeout_disabled = false;
-+ unsigned int ns_2clk = 0;
-+
-+ /* The Arasan has a bugette whereby it may lose the content of
-+ * successive writes to registers that are within two SD-card clock
-+ * cycles of each other (a clock domain crossing problem).
-+ * It seems, however, that the data register does not have this problem.
-+ * (Which is just as well - otherwise we'd have to nobble the DMA engine
-+ * too)
-+ */
-+ if (reg != SDHCI_BUFFER && host->clock != 0) {
-+ /* host->clock is the clock freq in Hz */
-+ static hptime_t last_write_hpt;
-+ hptime_t now = hptime();
-+ ns_2clk = cycle_delay*1000000/(host->clock/1000);
-+
-+ if (now == last_write_hpt || now == last_write_hpt+1) {
-+ /* we can't guarantee any significant time has
-+ * passed - we'll have to wait anyway ! */
-+ ndelay(ns_2clk);
-+ } else
-+ {
-+ /* we must have waited at least this many ns: */
-+ unsigned int ns_wait = HPTIME_CLK_NS *
-+ (last_write_hpt - now - 1);
-+ if (ns_wait < ns_2clk)
-+ ndelay(ns_2clk - ns_wait);
-+ }
-+ last_write_hpt = now;
-+ }
-+#if USE_SOFTWARE_TIMEOUTS
-+ /* The Arasan is clocked for timeouts using the SD clock which is too
-+ * fast for ERASE commands and causes issues. So we disable timeouts
-+ * for ERASE */
-+ if (host->cmd != NULL && host->cmd->opcode == MMC_ERASE &&
-+ reg == (SDHCI_COMMAND & ~3)) {
-+ mod_timer(&host->timer,
-+ jiffies + SOFTWARE_ERASE_TIMEOUT_SEC * HZ);
-+ ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ ier &= ~SDHCI_INT_DATA_TIMEOUT;
-+ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ timeout_disabled = true;
-+ ndelay(ns_2clk);
-+ } else if (timeout_disabled) {
-+ ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ ier |= SDHCI_INT_DATA_TIMEOUT;
-+ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-+ timeout_disabled = false;
-+ ndelay(ns_2clk);
-+ }
-+#endif
-+ writel(val, host->ioaddr + reg);
-+#else
-+ void __iomem * regaddr = host->ioaddr + reg;
-+
-+ writel(val, regaddr);
-+
-+ if (reg != SDHCI_BUFFER && reg != SDHCI_INT_STATUS && host->clock != 0)
-+ {
-+ int timeout = 100000;
-+ while (val != readl(regaddr) && --timeout > 0)
-+ continue;
-+
-+ if (timeout <= 0)
-+ printk(KERN_ERR "%s: writing 0x%X to reg 0x%X "
-+ "always gives 0x%X\n",
-+ mmc_hostname(host->mmc),
-+ val, reg, readl(regaddr));
-+ BUG_ON(timeout <= 0);
-+ }
-+#endif
-+}
-+
-+
-+void sdhci_bcm2708_writel(struct sdhci_host *host, u32 val, int reg)
-+{
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: writel to 0x%02x, value 0x%08x\n",
-+ mmc_hostname(host->mmc), reg, val);
-+#endif
-+ check_dma_reg_use(host, reg);
-+
-+ sdhci_bcm2708_raw_writel(host, val, reg);
-+}
-+
-+void sdhci_bcm2708_writew(struct sdhci_host *host, u16 val, int reg)
-+{
-+ static u32 shadow = 0;
-+
-+ u32 p = reg == SDHCI_COMMAND ? shadow :
-+ sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 s = reg << 3 & 0x18;
-+ u32 l = val << s;
-+ u32 m = 0xffff << s;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: writew to 0x%02x, value 0x%04x\n",
-+ mmc_hostname(host->mmc), reg, val);
-+#endif
-+
-+ if (reg == SDHCI_TRANSFER_MODE)
-+ shadow = (p & ~m) | l;
-+ else {
-+ check_dma_reg_use(host, reg);
-+ sdhci_bcm2708_raw_writel(host, (p & ~m) | l, reg & ~3);
-+ }
-+}
-+
-+void sdhci_bcm2708_writeb(struct sdhci_host *host, u8 val, int reg)
-+{
-+ u32 p = sdhci_bcm2708_raw_readl(host, reg & ~3);
-+ u32 s = reg << 3 & 0x18;
-+ u32 l = val << s;
-+ u32 m = 0xff << s;
-+
-+#ifdef LOG_REGISTERS
-+ printk(KERN_ERR "%s: writeb to 0x%02x, value 0x%02x\n",
-+ mmc_hostname(host->mmc), reg, val);
-+#endif
-+
-+ check_dma_reg_use(host, reg);
-+ sdhci_bcm2708_raw_writel(host, (p & ~m) | l, reg & ~3);
-+}
-+
-+static unsigned int sdhci_bcm2708_get_max_clock(struct sdhci_host *host)
-+{
-+ return emmc_clock_freq;
-+}
-+
-+/*****************************************************************************\
-+ * *
-+ * DMA Operation *
-+ * *
-+\*****************************************************************************/
-+
-+struct sdhci_bcm2708_priv {
-+ int dma_chan;
-+ int dma_irq;
-+ void __iomem *dma_chan_base;
-+ struct bcm2708_dma_cb *cb_base; /* DMA control blocks */
-+ dma_addr_t cb_handle;
-+ /* tracking scatter gather progress */
-+ unsigned sg_ix; /* scatter gather list index */
-+ unsigned sg_done; /* bytes in current sg_ix done */
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ unsigned char dma_wanted; /* DMA transfer requested */
-+ unsigned char dma_waits; /* wait states in DMAs */
-+#ifdef CHECK_DMA_USE
-+ unsigned char dmas_pending; /* no of unfinished DMAs */
-+ hptime_t when_started;
-+ hptime_t when_reset;
-+ hptime_t when_stopped;
-+#endif
-+#endif
-+ /* signalling the end of a transfer */
-+ void (*complete)(struct sdhci_host *);
-+};
-+
-+#define SDHCI_HOST_PRIV(host) \
-+ (struct sdhci_bcm2708_priv *)((struct sdhci_host *)(host)+1)
-+
-+
-+
-+#ifdef CHECK_DMA_REG_USE
-+static void check_dma_reg_use(struct sdhci_host *host, int reg)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ if (host_priv->dma_wanted && reg != SDHCI_INT_STATUS) {
-+ printk(KERN_INFO"%s: accessing register 0x%x during DMA\n",
-+ mmc_hostname(host->mmc), reg);
-+ }
-+}
-+#endif
-+
-+
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+
-+static void sdhci_clear_set_irqgen(struct sdhci_host *host, u32 clear, u32 set)
-+{
-+ u32 ier;
-+
-+ ier = sdhci_bcm2708_raw_readl(host, SDHCI_SIGNAL_ENABLE);
-+ ier &= ~clear;
-+ ier |= set;
-+ /* change which requests generate IRQs - makes no difference to
-+ the content of SDHCI_INT_STATUS, or the need to acknowledge IRQs */
-+ sdhci_bcm2708_raw_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-+}
-+
-+static void sdhci_signal_irqs(struct sdhci_host *host, u32 irqs)
-+{
-+ sdhci_clear_set_irqgen(host, 0, irqs);
-+}
-+
-+static void sdhci_unsignal_irqs(struct sdhci_host *host, u32 irqs)
-+{
-+ sdhci_clear_set_irqgen(host, irqs, 0);
-+}
-+
-+
-+
-+static void schci_bcm2708_cb_read(struct sdhci_bcm2708_priv *host,
-+ int ix,
-+ dma_addr_t dma_addr, unsigned len,
-+ int /*bool*/ is_last)
-+{
-+ struct bcm2708_dma_cb *cb = &host->cb_base[ix];
-+ unsigned char dmawaits = host->dma_waits;
-+
-+ cb->info = BCM2708_DMA_PER_MAP(BCM2708_DMA_DREQ_EMMC) |
-+ BCM2708_DMA_WAITS(dmawaits) |
-+ BCM2708_DMA_S_DREQ |
-+ BCM2708_DMA_D_WIDTH |
-+ BCM2708_DMA_D_INC;
-+ cb->src = DMA_SDHCI_BUFFER; /* DATA register DMA address */
-+ cb->dst = dma_addr;
-+ cb->length = len;
-+ cb->stride = 0;
-+
-+ if (is_last) {
-+ cb->info |= BCM2708_DMA_INT_EN |
-+ BCM2708_DMA_WAIT_RESP;
-+ cb->next = 0;
-+ } else
-+ cb->next = host->cb_handle +
-+ (ix+1)*sizeof(struct bcm2708_dma_cb);
-+
-+ cb->pad[0] = 0;
-+ cb->pad[1] = 0;
-+}
-+
-+static void schci_bcm2708_cb_write(struct sdhci_bcm2708_priv *host,
-+ int ix,
-+ dma_addr_t dma_addr, unsigned len,
-+ int /*bool*/ is_last)
-+{
-+ struct bcm2708_dma_cb *cb = &host->cb_base[ix];
-+ unsigned char dmawaits = host->dma_waits;
-+
-+ /* We can make arbitrarily large writes as long as we specify DREQ to
-+ pace the delivery of bytes to the Arasan hardware */
-+ cb->info = BCM2708_DMA_PER_MAP(BCM2708_DMA_DREQ_EMMC) |
-+ BCM2708_DMA_WAITS(dmawaits) |
-+ BCM2708_DMA_D_DREQ |
-+ BCM2708_DMA_S_WIDTH |
-+ BCM2708_DMA_S_INC;
-+ cb->src = dma_addr;
-+ cb->dst = DMA_SDHCI_BUFFER; /* DATA register DMA address */
-+ cb->length = len;
-+ cb->stride = 0;
-+
-+ if (is_last) {
-+ cb->info |= BCM2708_DMA_INT_EN |
-+ BCM2708_DMA_WAIT_RESP;
-+ cb->next = 0;
-+ } else
-+ cb->next = host->cb_handle +
-+ (ix+1)*sizeof(struct bcm2708_dma_cb);
-+
-+ cb->pad[0] = 0;
-+ cb->pad[1] = 0;
-+}
-+
-+
-+static void schci_bcm2708_dma_go(struct sdhci_host *host)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ void __iomem *dma_chan_base = host_priv->dma_chan_base;
-+
-+ BUG_ON(host_priv->dma_wanted);
-+#ifdef CHECK_DMA_USE
-+ if (host_priv->dma_wanted)
-+ printk(KERN_ERR "%s: DMA already in progress - "
-+ "now %"FMT_HPT", last started %lu "
-+ "reset %lu stopped %lu\n",
-+ mmc_hostname(host->mmc),
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ else if (host_priv->dmas_pending > 0)
-+ printk(KERN_INFO "%s: note - new DMA when %d reset DMAs "
-+ "already in progress - "
-+ "now %"FMT_HPT", started %lu reset %lu stopped %lu\n",
-+ mmc_hostname(host->mmc),
-+ host_priv->dmas_pending,
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ host_priv->dmas_pending += 1;
-+ host_priv->when_started = hptime();
-+#endif
-+ host_priv->dma_wanted = 1;
-+ DBG("PDMA go - base %p handle %08X\n", dma_chan_base,
-+ host_priv->cb_handle);
-+ bcm_dma_start(dma_chan_base, host_priv->cb_handle);
-+}
-+
-+
-+static void
-+sdhci_platdma_read(struct sdhci_host *host, dma_addr_t dma_addr, size_t len)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+
-+ DBG("PDMA to read %d bytes\n", len);
-+ host_priv->sg_done += len;
-+ schci_bcm2708_cb_read(host_priv, 0, dma_addr, len, 1/*TRUE*/);
-+ schci_bcm2708_dma_go(host);
-+}
-+
-+
-+static void
-+sdhci_platdma_write(struct sdhci_host *host, dma_addr_t dma_addr, size_t len)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+
-+ DBG("PDMA to write %d bytes\n", len);
-+ //BUG_ON(0 != (len & 0x1ff));
-+
-+ host_priv->sg_done += len;
-+ schci_bcm2708_cb_write(host_priv, 0, dma_addr, len, 1/*TRUE*/);
-+ schci_bcm2708_dma_go(host);
-+}
-+
-+/*! space is avaiable to receive into or data is available to write
-+ Platform DMA exported function
-+*/
-+void
-+sdhci_bcm2708_platdma_avail(struct sdhci_host *host, unsigned int *ref_intmask,
-+ void(*completion_callback)(struct sdhci_host *host))
-+{
-+ struct mmc_data *data = host->data;
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int sg_ix;
-+ size_t bytes;
-+ dma_addr_t addr;
-+
-+ BUG_ON(NULL == data);
-+ BUG_ON(0 == data->blksz);
-+
-+ host_priv->complete = completion_callback;
-+
-+ sg_ix = host_priv->sg_ix;
-+ BUG_ON(sg_ix >= data->sg_len);
-+
-+ /* we can DMA blocks larger than blksz - it may hang the DMA
-+ channel but we are its only user */
-+ bytes = sg_dma_len(&data->sg[sg_ix]) - host_priv->sg_done;
-+ addr = sg_dma_address(&data->sg[sg_ix]) + host_priv->sg_done;
-+
-+ if (bytes > 0) {
-+ /* We're going to poll for read/write available state until
-+ we finish this DMA
-+ */
-+
-+ if (data->flags & MMC_DATA_READ) {
-+ if (*ref_intmask & SDHCI_INT_DATA_AVAIL) {
-+ sdhci_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ sdhci_platdma_read(host, addr, bytes);
-+ }
-+ } else {
-+ if (*ref_intmask & SDHCI_INT_SPACE_AVAIL) {
-+ sdhci_unsignal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ sdhci_platdma_write(host, addr, bytes);
-+ }
-+ }
-+ }
-+ /* else:
-+ we have run out of bytes that need transferring (e.g. we may be in
-+ the middle of the last DMA transfer), or
-+ it is also possible that we've been called when another IRQ is
-+ signalled, even though we've turned off signalling of our own IRQ */
-+
-+ *ref_intmask &= ~SDHCI_INT_DATA_END;
-+ /* don't let the main sdhci driver act on this .. we'll deal with it
-+ when we respond to the DMA - if one is currently in progress */
-+}
-+
-+/* is it possible to DMA the given mmc_data structure?
-+ Platform DMA exported function
-+*/
-+int /*bool*/
-+sdhci_bcm2708_platdma_dmaable(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int ok = bcm_sg_suitable_for_dma(data->sg, data->sg_len);
-+
-+ if (!ok)
-+ DBG("Reverting to PIO - bad cache alignment\n");
-+
-+ else {
-+ host_priv->sg_ix = 0; /* first SG index */
-+ host_priv->sg_done = 0; /* no bytes done */
-+ }
-+
-+ return ok;
-+}
-+
-+#include <mach/arm_control.h> //GRAYG
-+/*! the current SD transacton has been abandonned
-+ We need to tidy up if we were in the middle of a DMA
-+ Platform DMA exported function
-+*/
-+void
-+sdhci_bcm2708_platdma_reset(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+// unsigned long flags;
-+
-+ BUG_ON(NULL == host);
-+
-+// spin_lock_irqsave(&host->lock, flags);
-+
-+ if (host_priv->dma_wanted) {
-+ if (NULL == data) {
-+ printk(KERN_ERR "%s: ongoing DMA reset - no data!\n",
-+ mmc_hostname(host->mmc));
-+ BUG_ON(NULL == data);
-+ } else {
-+ struct scatterlist *sg;
-+ int sg_len;
-+ int sg_todo;
-+ int rc;
-+ unsigned long cs;
-+
-+ sg = data->sg;
-+ sg_len = data->sg_len;
-+ sg_todo = sg_dma_len(&sg[host_priv->sg_ix]);
-+
-+ cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
-+
-+ if (!(BCM2708_DMA_ACTIVE & cs))
-+ {
-+ if (extra_messages)
-+ printk(KERN_INFO "%s: missed completion of "
-+ "cmd %d DMA (%d/%d [%d]/[%d]) - "
-+ "ignoring it\n",
-+ mmc_hostname(host->mmc),
-+ host->last_cmdop,
-+ host_priv->sg_done, sg_todo,
-+ host_priv->sg_ix+1, sg_len);
-+ }
-+ else
-+ printk(KERN_INFO "%s: resetting ongoing cmd %d"
-+ "DMA before %d/%d [%d]/[%d] complete\n",
-+ mmc_hostname(host->mmc),
-+ host->last_cmdop,
-+ host_priv->sg_done, sg_todo,
-+ host_priv->sg_ix+1, sg_len);
-+#ifdef CHECK_DMA_USE
-+ printk(KERN_INFO "%s: now %"FMT_HPT" started %lu "
-+ "last reset %lu last stopped %lu\n",
-+ mmc_hostname(host->mmc),
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ { unsigned long info, debug;
-+ void __iomem *base;
-+ unsigned long pend0, pend1, pend2;
-+
-+ base = host_priv->dma_chan_base;
-+ cs = readl(base + BCM2708_DMA_CS);
-+ info = readl(base + BCM2708_DMA_INFO);
-+ debug = readl(base + BCM2708_DMA_DEBUG);
-+ printk(KERN_INFO "%s: DMA%d CS=%08lX TI=%08lX "
-+ "DEBUG=%08lX\n",
-+ mmc_hostname(host->mmc),
-+ host_priv->dma_chan,
-+ cs, info, debug);
-+ pend0 = readl(__io_address(ARM_IRQ_PEND0));
-+ pend1 = readl(__io_address(ARM_IRQ_PEND1));
-+ pend2 = readl(__io_address(ARM_IRQ_PEND2));
-+
-+ printk(KERN_INFO "%s: PEND0=%08lX "
-+ "PEND1=%08lX PEND2=%08lX\n",
-+ mmc_hostname(host->mmc),
-+ pend0, pend1, pend2);
-+
-+ //gintsts = readl(__io_address(GINTSTS));
-+ //gintmsk = readl(__io_address(GINTMSK));
-+ //printk(KERN_INFO "%s: USB GINTSTS=%08lX"
-+ // "GINTMSK=%08lX\n",
-+ // mmc_hostname(host->mmc), gintsts, gintmsk);
-+ }
-+#endif
-+ rc = bcm_dma_abort(host_priv->dma_chan_base);
-+ BUG_ON(rc != 0);
-+ }
-+ host_priv->dma_wanted = 0;
-+#ifdef CHECK_DMA_USE
-+ host_priv->when_reset = hptime();
-+#endif
-+ }
-+
-+// spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+
-+static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host,
-+ u32 dma_cs)
-+{
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ struct mmc_data *data;
-+ struct scatterlist *sg;
-+ int sg_len;
-+ int sg_ix;
-+ int sg_todo;
-+// unsigned long flags;
-+
-+ BUG_ON(NULL == host);
-+
-+// spin_lock_irqsave(&host->lock, flags);
-+ data = host->data;
-+
-+#ifdef CHECK_DMA_USE
-+ if (host_priv->dmas_pending <= 0)
-+ DBG("on completion no DMA in progress - "
-+ "now %"FMT_HPT" started %lu reset %lu stopped %lu\n",
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ else if (host_priv->dmas_pending > 1)
-+ DBG("still %d DMA in progress after completion - "
-+ "now %"FMT_HPT" started %lu reset %lu stopped %lu\n",
-+ host_priv->dmas_pending - 1,
-+ hptime(), since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ BUG_ON(host_priv->dmas_pending <= 0);
-+ host_priv->dmas_pending -= 1;
-+ host_priv->when_stopped = hptime();
-+#endif
-+ host_priv->dma_wanted = 0;
-+
-+ if (NULL == data) {
-+ DBG("PDMA unused completion - status 0x%X\n", dma_cs);
-+// spin_unlock_irqrestore(&host->lock, flags);
-+ return;
-+ }
-+ sg = data->sg;
-+ sg_len = data->sg_len;
-+ sg_todo = sg_dma_len(&sg[host_priv->sg_ix]);
-+
-+ DBG("PDMA complete %d/%d [%d]/[%d]..\n",
-+ host_priv->sg_done, sg_todo,
-+ host_priv->sg_ix+1, sg_len);
-+
-+ BUG_ON(host_priv->sg_done > sg_todo);
-+
-+ if (host_priv->sg_done >= sg_todo) {
-+ host_priv->sg_ix++;
-+ host_priv->sg_done = 0;
-+ }
-+
-+ sg_ix = host_priv->sg_ix;
-+ if (sg_ix < sg_len) {
-+ u32 irq_mask;
-+ /* Set off next DMA if we've got the capacity */
-+
-+ if (data->flags & MMC_DATA_READ)
-+ irq_mask = SDHCI_INT_DATA_AVAIL;
-+ else
-+ irq_mask = SDHCI_INT_SPACE_AVAIL;
-+
-+ /* We have to use the interrupt status register on the BCM2708
-+ rather than the SDHCI_PRESENT_STATE register because latency
-+ in the glue logic means that the information retrieved from
-+ the latter is not always up-to-date w.r.t the DMA engine -
-+ it may not indicate that a read or a write is ready yet */
-+ if (sdhci_bcm2708_raw_readl(host, SDHCI_INT_STATUS) &
-+ irq_mask) {
-+ size_t bytes = sg_dma_len(&sg[sg_ix]) -
-+ host_priv->sg_done;
-+ dma_addr_t addr = sg_dma_address(&data->sg[sg_ix]) +
-+ host_priv->sg_done;
-+
-+ /* acknowledge interrupt */
-+ sdhci_bcm2708_raw_writel(host, irq_mask,
-+ SDHCI_INT_STATUS);
-+
-+ BUG_ON(0 == bytes);
-+
-+ if (data->flags & MMC_DATA_READ)
-+ sdhci_platdma_read(host, addr, bytes);
-+ else
-+ sdhci_platdma_write(host, addr, bytes);
-+ } else {
-+ DBG("PDMA - wait avail\n");
-+ /* may generate an IRQ if already present */
-+ sdhci_signal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ }
-+ } else {
-+ if (sync_after_dma) {
-+ /* On the Arasan controller the stop command (which will be
-+ scheduled after this completes) does not seem to work
-+ properly if we allow it to be issued when we are
-+ transferring data to/from the SD card.
-+ We get CRC and DEND errors unless we wait for
-+ the SD controller to finish reading/writing to the card. */
-+ u32 state_mask;
-+ int timeout=3*1000*1000;
-+
-+ DBG("PDMA over - sync card\n");
-+ if (data->flags & MMC_DATA_READ)
-+ state_mask = SDHCI_DOING_READ;
-+ else
-+ state_mask = SDHCI_DOING_WRITE;
-+
-+ while (0 != (sdhci_bcm2708_raw_readl(host, SDHCI_PRESENT_STATE)
-+ & state_mask) && --timeout > 0)
-+ {
-+ udelay(1);
-+ continue;
-+ }
-+ if (timeout <= 0)
-+ printk(KERN_ERR"%s: final %s to SD card still "
-+ "running\n",
-+ mmc_hostname(host->mmc),
-+ data->flags & MMC_DATA_READ? "read": "write");
-+ }
-+ if (host_priv->complete) {
-+ (*host_priv->complete)(host);
-+ DBG("PDMA %s complete\n",
-+ data->flags & MMC_DATA_READ?"read":"write");
-+ sdhci_signal_irqs(host, SDHCI_INT_DATA_AVAIL |
-+ SDHCI_INT_SPACE_AVAIL);
-+ }
-+ }
-+// spin_unlock_irqrestore(&host->lock, flags);
-+}
-+
-+static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id)
-+{
-+ irqreturn_t result = IRQ_NONE;
-+ struct sdhci_host *host = dev_id;
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ u32 dma_cs; /* control and status register */
-+
-+ BUG_ON(NULL == dev_id);
-+ BUG_ON(NULL == host_priv->dma_chan_base);
-+
-+ sdhci_spin_lock(host);
-+
-+ dma_cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS);
-+
-+ if (dma_cs & BCM2708_DMA_ERR) {
-+ unsigned long debug;
-+ debug = readl(host_priv->dma_chan_base +
-+ BCM2708_DMA_DEBUG);
-+ printk(KERN_ERR "%s: DMA error - CS %lX DEBUG %lX\n",
-+ mmc_hostname(host->mmc), (unsigned long)dma_cs,
-+ (unsigned long)debug);
-+ /* reset error */
-+ writel(debug, host_priv->dma_chan_base +
-+ BCM2708_DMA_DEBUG);
-+ }
-+ if (dma_cs & BCM2708_DMA_INT) {
-+ /* acknowledge interrupt */
-+ writel(BCM2708_DMA_INT,
-+ host_priv->dma_chan_base + BCM2708_DMA_CS);
-+
-+ dsb(); /* ARM data synchronization (push) operation */
-+
-+ if (!host_priv->dma_wanted) {
-+ /* ignore this interrupt - it was reset */
-+ if (extra_messages)
-+ printk(KERN_INFO "%s: DMA IRQ %X ignored - "
-+ "results were reset\n",
-+ mmc_hostname(host->mmc), dma_cs);
-+#ifdef CHECK_DMA_USE
-+ printk(KERN_INFO "%s: now %"FMT_HPT
-+ " started %lu reset %lu stopped %lu\n",
-+ mmc_hostname(host->mmc), hptime(),
-+ since_ns(host_priv->when_started),
-+ since_ns(host_priv->when_reset),
-+ since_ns(host_priv->when_stopped));
-+ host_priv->dmas_pending--;
-+#endif
-+ } else
-+ sdhci_bcm2708_dma_complete_irq(host, dma_cs);
-+
-+ result = IRQ_HANDLED;
-+ }
-+ sdhci_spin_unlock(host);
-+
-+ return result;
-+}
-+#endif /* CONFIG_MMC_SDHCI_BCM2708_DMA */
-+
-+
-+/***************************************************************************** \
-+ * *
-+ * Device Attributes *
-+ * *
-+\*****************************************************************************/
-+
-+
-+/**
-+ * Show the DMA-using status
-+ */
-+static ssize_t attr_dma_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+ int use_dma = (host->flags & SDHCI_USE_PLATDMA? 1:0);
-+ return sprintf(buf, "%d\n", use_dma);
-+ } else
-+ return -EINVAL;
-+}
-+
-+/**
-+ * Set the DMA-using status
-+ */
-+static ssize_t attr_dma_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ int on = simple_strtol(buf, NULL, 0);
-+ if (on) {
-+ host->flags |= SDHCI_USE_PLATDMA;
-+ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN);
-+ printk(KERN_INFO "%s: DMA enabled\n",
-+ mmc_hostname(host->mmc));
-+ } else {
-+ host->flags &= ~(SDHCI_USE_PLATDMA | SDHCI_REQ_USE_DMA);
-+ sdhci_bcm2708_writel(host, 0, REG_EXRDFIFO_EN);
-+ printk(KERN_INFO "%s: DMA disabled\n",
-+ mmc_hostname(host->mmc));
-+ }
-+#endif
-+ return count;
-+ } else
-+ return -EINVAL;
-+}
-+
-+static DEVICE_ATTR(use_dma, S_IRUGO | S_IWUGO, attr_dma_show, attr_dma_store);
-+
-+
-+/**
-+ * Show the DMA wait states used
-+ */
-+static ssize_t attr_dmawait_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int dmawait = host_priv->dma_waits;
-+ return sprintf(buf, "%d\n", dmawait);
-+ } else
-+ return -EINVAL;
-+}
-+
-+/**
-+ * Set the DMA wait state used
-+ */
-+static ssize_t attr_dmawait_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int dma_waits = simple_strtol(buf, NULL, 0);
-+ if (dma_waits >= 0 && dma_waits < 32)
-+ host_priv->dma_waits = dma_waits;
-+ else
-+ printk(KERN_ERR "%s: illegal dma_waits value - %d",
-+ mmc_hostname(host->mmc), dma_waits);
-+#endif
-+ return count;
-+ } else
-+ return -EINVAL;
-+}
-+
-+static DEVICE_ATTR(dma_wait, S_IRUGO | S_IWUGO,
-+ attr_dmawait_show, attr_dmawait_store);
-+
-+
-+/**
-+ * Show the DMA-using status
-+ */
-+static ssize_t attr_status_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)dev_get_drvdata(_dev);
-+
-+ if (host) {
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ return sprintf(buf,
-+ "present: yes\n"
-+ "power: %s\n"
-+ "clock: %u Hz\n"
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ "dma: %s (%d waits)\n",
-+#else
-+ "dma: unconfigured\n",
-+#endif
-+ "always on",
-+ host->clock
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ , (host->flags & SDHCI_USE_PLATDMA)? "on": "off"
-+ , host_priv->dma_waits
-+#endif
-+ );
-+ } else
-+ return -EINVAL;
-+}
-+
-+static DEVICE_ATTR(status, S_IRUGO, attr_status_show, NULL);
-+
-+/***************************************************************************** \
-+ * *
-+ * Power Management *
-+ * *
-+\*****************************************************************************/
-+
-+
-+#ifdef CONFIG_PM
-+static int sdhci_bcm2708_suspend(struct platform_device *dev, pm_message_t state)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)
-+ platform_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host->mmc) {
-+ ret = mmc_suspend_host(host->mmc);
-+ }
-+
-+ return ret;
-+}
-+
-+static int sdhci_bcm2708_resume(struct platform_device *dev)
-+{
-+ struct sdhci_host *host = (struct sdhci_host *)
-+ platform_get_drvdata(dev);
-+ int ret = 0;
-+
-+ if (host->mmc) {
-+ ret = mmc_resume_host(host->mmc);
-+ }
-+
-+ return ret;
-+}
-+#endif
-+
-+
-+/*****************************************************************************\
-+ * *
-+ * Device quirk functions. Implemented as local ops because the flags *
-+ * field is out of space with newer kernels. This implementation can be *
-+ * back ported to older kernels as well. *
-+\****************************************************************************/
-+static unsigned int sdhci_bcm2708_quirk_extra_ints(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_quirk_spurious_crc_acmd51(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_quirk_voltage_broken(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_uhs_broken(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+static unsigned int sdhci_bcm2708_missing_status(struct sdhci_host *host)
-+{
-+ return 1;
-+}
-+
-+/***************************************************************************** \
-+ * *
-+ * Device ops *
-+ * *
-+\*****************************************************************************/
-+
-+static struct sdhci_ops sdhci_bcm2708_ops = {
-+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-+ .read_l = sdhci_bcm2708_readl,
-+ .read_w = sdhci_bcm2708_readw,
-+ .read_b = sdhci_bcm2708_readb,
-+ .write_l = sdhci_bcm2708_writel,
-+ .write_w = sdhci_bcm2708_writew,
-+ .write_b = sdhci_bcm2708_writeb,
-+#else
-+#error The BCM2708 SDHCI driver needs CONFIG_MMC_SDHCI_IO_ACCESSORS to be set
-+#endif
-+ .get_max_clock = sdhci_bcm2708_get_max_clock,
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ // Platform DMA operations
-+ .pdma_able = sdhci_bcm2708_platdma_dmaable,
-+ .pdma_avail = sdhci_bcm2708_platdma_avail,
-+ .pdma_reset = sdhci_bcm2708_platdma_reset,
-+#endif
-+ .extra_ints = sdhci_bcm2708_quirk_extra_ints,
-+ .voltage_broken = sdhci_bcm2708_quirk_voltage_broken,
-+ .uhs_broken = sdhci_bcm2708_uhs_broken,
-+};
-+
-+/*****************************************************************************\
-+ * *
-+ * Device probing/removal *
-+ * *
-+\*****************************************************************************/
-+
-+static int sdhci_bcm2708_probe(struct platform_device *pdev)
-+{
-+ struct sdhci_host *host;
-+ struct resource *iomem;
-+ struct sdhci_bcm2708_priv *host_priv;
-+ int ret;
-+
-+ BUG_ON(pdev == NULL);
-+
-+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!iomem) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ if (resource_size(iomem) != 0x100)
-+ dev_err(&pdev->dev, "Invalid iomem size. You may "
-+ "experience problems.\n");
-+
-+ if (pdev->dev.parent)
-+ host = sdhci_alloc_host(pdev->dev.parent,
-+ sizeof(struct sdhci_bcm2708_priv));
-+ else
-+ host = sdhci_alloc_host(&pdev->dev,
-+ sizeof(struct sdhci_bcm2708_priv));
-+
-+ if (IS_ERR(host)) {
-+ ret = PTR_ERR(host);
-+ goto err;
-+ }
-+ if (missing_status) {
-+ sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status;
-+ }
-+
-+ if( spurious_crc_acmd51 ) {
-+ sdhci_bcm2708_ops.spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc_acmd51;
-+ }
-+
-+
-+ printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable");
-+
-+ host->hw_name = "BCM2708_Arasan";
-+ host->ops = &sdhci_bcm2708_ops;
-+ host->irq = platform_get_irq(pdev, 0);
-+ host->second_irq = 0;
-+
-+ host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-+ SDHCI_QUIRK_MISSING_CAPS |
-+ SDHCI_QUIRK_NO_HISPD_BIT |
-+ (sync_after_dma ? 0:SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12);
-+
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ host->flags = SDHCI_USE_PLATDMA;
-+#endif
-+
-+ if (!request_mem_region(iomem->start, resource_size(iomem),
-+ mmc_hostname(host->mmc))) {
-+ dev_err(&pdev->dev, "cannot request region\n");
-+ ret = -EBUSY;
-+ goto err_request;
-+ }
-+
-+ host->ioaddr = ioremap(iomem->start, resource_size(iomem));
-+ if (!host->ioaddr) {
-+ dev_err(&pdev->dev, "failed to remap registers\n");
-+ ret = -ENOMEM;
-+ goto err_remap;
-+ }
-+
-+ host_priv = SDHCI_HOST_PRIV(host);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ host_priv->dma_wanted = 0;
-+#ifdef CHECK_DMA_USE
-+ host_priv->dmas_pending = 0;
-+ host_priv->when_started = 0;
-+ host_priv->when_reset = 0;
-+ host_priv->when_stopped = 0;
-+#endif
-+ host_priv->sg_ix = 0;
-+ host_priv->sg_done = 0;
-+ host_priv->complete = NULL;
-+ host_priv->dma_waits = SDHCI_BCM_DMA_WAITS;
-+
-+ host_priv->cb_base = dma_alloc_writecombine(&pdev->dev, SZ_4K,
-+ &host_priv->cb_handle,
-+ GFP_KERNEL);
-+ if (!host_priv->cb_base) {
-+ dev_err(&pdev->dev, "cannot allocate DMA CBs\n");
-+ ret = -ENOMEM;
-+ goto err_alloc_cb;
-+ }
-+
-+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST,
-+ &host_priv->dma_chan_base,
-+ &host_priv->dma_irq);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "couldn't allocate a DMA channel\n");
-+ goto err_add_dma;
-+ }
-+ host_priv->dma_chan = ret;
-+
-+ ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq,0,//IRQF_SHARED,
-+ DRIVER_NAME " (dma)", host);
-+ if (ret) {
-+ dev_err(&pdev->dev, "cannot set DMA IRQ\n");
-+ goto err_add_dma_irq;
-+ }
-+ host->second_irq = host_priv->dma_irq;
-+ DBG("DMA CBs %p handle %08X DMA%d %p DMA IRQ %d\n",
-+ host_priv->cb_base, (unsigned)host_priv->cb_handle,
-+ host_priv->dma_chan, host_priv->dma_chan_base,
-+ host_priv->dma_irq);
-+
-+ if (allow_highspeed)
-+ host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-+
-+ /* single block writes cause data loss with some SD cards! */
-+ host->mmc->caps2 |= MMC_CAP2_FORCE_MULTIBLOCK;
-+#endif
-+
-+ ret = sdhci_add_host(host);
-+ if (ret)
-+ goto err_add_host;
-+
-+ platform_set_drvdata(pdev, host);
-+ ret = device_create_file(&pdev->dev, &dev_attr_use_dma);
-+ ret = device_create_file(&pdev->dev, &dev_attr_dma_wait);
-+ ret = device_create_file(&pdev->dev, &dev_attr_status);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ /* enable extension fifo for paced DMA transfers */
-+ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN);
-+ sdhci_bcm2708_writel(host, 4, REG_EXRDFIFO_CFG);
-+#endif
-+
-+ printk(KERN_INFO "%s: BCM2708 SDHC host at 0x%08llx DMA %d IRQ %d\n",
-+ mmc_hostname(host->mmc), (unsigned long long)iomem->start,
-+ host_priv->dma_chan, host_priv->dma_irq);
-+
-+ return 0;
-+
-+err_add_host:
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ free_irq(host_priv->dma_irq, host);
-+err_add_dma_irq:
-+ bcm_dma_chan_free(host_priv->dma_chan);
-+err_add_dma:
-+ dma_free_writecombine(&pdev->dev, SZ_4K, host_priv->cb_base,
-+ host_priv->cb_handle);
-+err_alloc_cb:
-+#endif
-+ iounmap(host->ioaddr);
-+err_remap:
-+ release_mem_region(iomem->start, resource_size(iomem));
-+err_request:
-+ sdhci_free_host(host);
-+err:
-+ dev_err(&pdev->dev, "probe failed, err %d\n", ret);
-+ return ret;
-+}
-+
-+static int sdhci_bcm2708_remove(struct platform_device *pdev)
-+{
-+ struct sdhci_host *host = platform_get_drvdata(pdev);
-+ struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host);
-+ int dead;
-+ u32 scratch;
-+
-+ dead = 0;
-+ scratch = sdhci_bcm2708_readl(host, SDHCI_INT_STATUS);
-+ if (scratch == (u32)-1)
-+ dead = 1;
-+
-+ device_remove_file(&pdev->dev, &dev_attr_status);
-+ device_remove_file(&pdev->dev, &dev_attr_dma_wait);
-+ device_remove_file(&pdev->dev, &dev_attr_use_dma);
-+
-+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA
-+ free_irq(host_priv->dma_irq, host);
-+ dma_free_writecombine(&pdev->dev, SZ_4K, host_priv->cb_base,
-+ host_priv->cb_handle);
-+#endif
-+ sdhci_remove_host(host, dead);
-+ iounmap(host->ioaddr);
-+ release_mem_region(iomem->start, resource_size(iomem));
-+ sdhci_free_host(host);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver sdhci_bcm2708_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = sdhci_bcm2708_probe,
-+ .remove = sdhci_bcm2708_remove,
-+
-+#ifdef CONFIG_PM
-+ .suspend = sdhci_bcm2708_suspend,
-+ .resume = sdhci_bcm2708_resume,
-+#endif
-+
-+};
-+
-+/*****************************************************************************\
-+ * *
-+ * Driver init/exit *
-+ * *
-+\*****************************************************************************/
-+
-+static int __init sdhci_drv_init(void)
-+{
-+ return platform_driver_register(&sdhci_bcm2708_driver);
-+}
-+
-+static void __exit sdhci_drv_exit(void)
-+{
-+ platform_driver_unregister(&sdhci_bcm2708_driver);
-+}
-+
-+module_init(sdhci_drv_init);
-+module_exit(sdhci_drv_exit);
-+
-+module_param(allow_highspeed, bool, 0444);
-+module_param(emmc_clock_freq, int, 0444);
-+module_param(sync_after_dma, bool, 0444);
-+module_param(missing_status, bool, 0444);
-+module_param(spurious_crc_acmd51, bool, 0444);
-+module_param(enable_llm, bool, 0444);
-+module_param(cycle_delay, int, 0444);
-+module_param(extra_messages, bool, 0444);
-+
-+MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
-+MODULE_AUTHOR("Broadcom <info@broadcom.com>");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-+
-+MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes");
-+MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock");
-+MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete");
-+MODULE_PARM_DESC(missing_status, "Use the missing status quirk");
-+MODULE_PARM_DESC(spurious_crc_acmd51, "Use the spurious crc quirk for reading SCR (ACMD51)");
-+MODULE_PARM_DESC(enable_llm, "Enable low-latency mode");
-+MODULE_PARM_DESC(extra_messages, "Enable more sdcard warning messages");
-+
-+
-diff -Nur linux-3.11.10.orig/drivers/mmc/host/sdhci.c linux-3.11.10/drivers/mmc/host/sdhci.c
---- linux-3.11.10.orig/drivers/mmc/host/sdhci.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/host/sdhci.c 2014-02-07 19:57:28.000000000 +0100
-@@ -28,6 +28,7 @@
- #include <linux/mmc/mmc.h>
- #include <linux/mmc/host.h>
- #include <linux/mmc/card.h>
-+#include <linux/mmc/sd.h>
- #include <linux/mmc/slot-gpio.h>
-
- #include "sdhci.h"
-@@ -131,6 +132,91 @@
- * Low level functions *
- * *
- \*****************************************************************************/
-+extern bool enable_llm;
-+static int sdhci_locked=0;
-+void sdhci_spin_lock(struct sdhci_host *host)
-+{
-+ spin_lock(&host->lock);
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ disable_irq_nosync(host->irq);
-+ if(host->second_irq)
-+ disable_irq_nosync(host->second_irq);
-+ local_irq_enable();
-+ }
-+#endif
-+}
-+
-+void sdhci_spin_unlock(struct sdhci_host *host)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ local_irq_disable();
-+ if(host->second_irq)
-+ enable_irq(host->second_irq);
-+ enable_irq(host->irq);
-+ }
-+#endif
-+ spin_unlock(&host->lock);
-+}
-+
-+void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ while(sdhci_locked)
-+ {
-+ preempt_schedule();
-+ }
-+ spin_lock_irqsave(&host->lock,*flags);
-+ disable_irq(host->irq);
-+ if(host->second_irq)
-+ disable_irq(host->second_irq);
-+ local_irq_enable();
-+ }
-+ else
-+#endif
-+ spin_lock_irqsave(&host->lock,*flags);
-+}
-+
-+void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ local_irq_disable();
-+ if(host->second_irq)
-+ enable_irq(host->second_irq);
-+ enable_irq(host->irq);
-+ }
-+#endif
-+ spin_unlock_irqrestore(&host->lock,flags);
-+}
-+
-+static void sdhci_spin_enable_schedule(struct sdhci_host *host)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ sdhci_locked = 1;
-+ preempt_enable();
-+ }
-+#endif
-+}
-+
-+static void sdhci_spin_disable_schedule(struct sdhci_host *host)
-+{
-+#ifdef CONFIG_PREEMPT
-+ if(enable_llm)
-+ {
-+ preempt_disable();
-+ sdhci_locked = 0;
-+ }
-+#endif
-+}
-
- static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
- {
-@@ -300,7 +386,7 @@
- struct sdhci_host *host = container_of(led, struct sdhci_host, led);
- unsigned long flags;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->runtime_suspended)
- goto out;
-@@ -310,7 +396,7 @@
- else
- sdhci_activate_led(host);
- out:
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
- #endif
-
-@@ -327,7 +413,7 @@
- u32 uninitialized_var(scratch);
- u8 *buf;
-
-- DBG("PIO reading\n");
-+ DBG("PIO reading %db\n", host->data->blksz);
-
- blksize = host->data->blksz;
- chunk = 0;
-@@ -372,7 +458,7 @@
- u32 scratch;
- u8 *buf;
-
-- DBG("PIO writing\n");
-+ DBG("PIO writing %db\n", host->data->blksz);
-
- blksize = host->data->blksz;
- chunk = 0;
-@@ -411,19 +497,28 @@
- local_irq_restore(flags);
- }
-
--static void sdhci_transfer_pio(struct sdhci_host *host)
-+static void sdhci_transfer_pio(struct sdhci_host *host, u32 intstate)
- {
- u32 mask;
-+ u32 state = 0;
-+ u32 intmask;
-+ int available;
-
- BUG_ON(!host->data);
-
- if (host->blocks == 0)
- return;
-
-- if (host->data->flags & MMC_DATA_READ)
-+ if (host->data->flags & MMC_DATA_READ) {
- mask = SDHCI_DATA_AVAILABLE;
-- else
-+ intmask = SDHCI_INT_DATA_AVAIL;
-+ } else {
- mask = SDHCI_SPACE_AVAILABLE;
-+ intmask = SDHCI_INT_SPACE_AVAIL;
-+ }
-+
-+ /* initially we can see whether we can procede using intstate */
-+ available = (intstate & intmask);
-
- /*
- * Some controllers (JMicron JMB38x) mess up the buffer bits
-@@ -434,7 +529,7 @@
- (host->data->blocks == 1))
- mask = ~0;
-
-- while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
-+ while (available) {
- if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
- udelay(100);
-
-@@ -446,9 +541,11 @@
- host->blocks--;
- if (host->blocks == 0)
- break;
-+ state = sdhci_readl(host, SDHCI_PRESENT_STATE);
-+ available = state & mask;
- }
-
-- DBG("PIO transfer complete.\n");
-+ DBG("PIO transfer complete - %d blocks left.\n", host->blocks);
- }
-
- static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
-@@ -721,7 +818,9 @@
- u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
- u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
-
-- if (host->flags & SDHCI_REQ_USE_DMA)
-+ /* platform DMA will begin on receipt of PIO irqs */
-+ if ((host->flags & SDHCI_REQ_USE_DMA) &&
-+ !(host->flags & SDHCI_USE_PLATDMA))
- sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
- else
- sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
-@@ -753,44 +852,25 @@
- host->data_early = 0;
- host->data->bytes_xfered = 0;
-
-- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
-+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA | SDHCI_USE_PLATDMA))
- host->flags |= SDHCI_REQ_USE_DMA;
-
- /*
- * FIXME: This doesn't account for merging when mapping the
- * scatterlist.
- */
-- if (host->flags & SDHCI_REQ_USE_DMA) {
-- int broken, i;
-- struct scatterlist *sg;
--
-- broken = 0;
-- if (host->flags & SDHCI_USE_ADMA) {
-- if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
-- broken = 1;
-- } else {
-- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
-- broken = 1;
-- }
--
-- if (unlikely(broken)) {
-- for_each_sg(data->sg, sg, data->sg_len, i) {
-- if (sg->length & 0x3) {
-- DBG("Reverting to PIO because of "
-- "transfer size (%d)\n",
-- sg->length);
-- host->flags &= ~SDHCI_REQ_USE_DMA;
-- break;
-- }
-- }
-- }
-- }
-
- /*
- * The assumption here being that alignment is the same after
- * translation to device address space.
- */
-- if (host->flags & SDHCI_REQ_USE_DMA) {
-+ if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_PLATDMA)) ==
-+ (SDHCI_REQ_USE_DMA | SDHCI_USE_PLATDMA)) {
-+
-+ if (! sdhci_platdma_dmaable(host, data))
-+ host->flags &= ~SDHCI_REQ_USE_DMA;
-+
-+ } else if (host->flags & SDHCI_REQ_USE_DMA) {
- int broken, i;
- struct scatterlist *sg;
-
-@@ -849,7 +929,8 @@
- */
- WARN_ON(1);
- host->flags &= ~SDHCI_REQ_USE_DMA;
-- } else {
-+ } else
-+ if (!(host->flags & SDHCI_USE_PLATDMA)) {
- WARN_ON(sg_cnt != 1);
- sdhci_writel(host, sg_dma_address(data->sg),
- SDHCI_DMA_ADDRESS);
-@@ -865,11 +946,13 @@
- if (host->version >= SDHCI_SPEC_200) {
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
-+ if (! (host->flags & SDHCI_USE_PLATDMA)) {
- if ((host->flags & SDHCI_REQ_USE_DMA) &&
- (host->flags & SDHCI_USE_ADMA))
- ctrl |= SDHCI_CTRL_ADMA32;
- else
- ctrl |= SDHCI_CTRL_SDMA;
-+ }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- }
-
-@@ -921,7 +1004,8 @@
-
- if (data->flags & MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
-- if (host->flags & SDHCI_REQ_USE_DMA)
-+ if ((host->flags & SDHCI_REQ_USE_DMA) &&
-+ !(host->flags & SDHCI_USE_PLATDMA))
- mode |= SDHCI_TRNS_DMA;
-
- sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
-@@ -937,13 +1021,16 @@
- host->data = NULL;
-
- if (host->flags & SDHCI_REQ_USE_DMA) {
-- if (host->flags & SDHCI_USE_ADMA)
-- sdhci_adma_table_post(host, data);
-- else {
-+ /* we may have to abandon an ongoing platform DMA */
-+ if (host->flags & SDHCI_USE_PLATDMA)
-+ sdhci_platdma_reset(host, data);
-+
-+ if (host->flags & (SDHCI_USE_PLATDMA | SDHCI_USE_SDMA)) {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
-- }
-+ } else if (host->flags & SDHCI_USE_ADMA)
-+ sdhci_adma_table_post(host, data);
- }
-
- /*
-@@ -996,6 +1083,12 @@
- if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
- mask |= SDHCI_DATA_INHIBIT;
-
-+ if(host->ops->missing_status && (cmd->opcode == MMC_SEND_STATUS)) {
-+ timeout = 5000; // Really obscenely large delay to send the status, due to bug in controller
-+ // which might cause the STATUS command to get stuck when a data operation is in flow
-+ mask |= SDHCI_DATA_INHIBIT;
-+ }
-+
- /* We shouldn't wait for data inihibit for stop commands, even
- though they might use busy signaling */
- if (host->mrq->data && (cmd == host->mrq->data->stop))
-@@ -1011,12 +1104,20 @@
- return;
- }
- timeout--;
-+ sdhci_spin_enable_schedule(host);
- mdelay(1);
-+ sdhci_spin_disable_schedule(host);
- }
-+ DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask,
-+ sdhci_readl(host, SDHCI_INT_STATUS));
-
- mod_timer(&host->timer, jiffies + 10 * HZ);
-
- host->cmd = cmd;
-+ if (host->last_cmdop == MMC_APP_CMD)
-+ host->last_cmdop = -cmd->opcode;
-+ else
-+ host->last_cmdop = cmd->opcode;
-
- sdhci_prepare_data(host, cmd);
-
-@@ -1232,7 +1333,9 @@
- return;
- }
- timeout--;
-+ sdhci_spin_enable_schedule(host);
- mdelay(1);
-+ sdhci_spin_disable_schedule(host);
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
-@@ -1333,7 +1436,7 @@
-
- sdhci_runtime_pm_get(host);
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- WARN_ON(host->mrq != NULL);
-
-@@ -1391,9 +1494,9 @@
- mmc->card->type == MMC_TYPE_MMC ?
- MMC_SEND_TUNING_BLOCK_HS200 :
- MMC_SEND_TUNING_BLOCK;
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- sdhci_execute_tuning(mmc, tuning_opcode);
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- /* Restore original mmc_request structure */
- host->mrq = mrq;
-@@ -1407,7 +1510,7 @@
- }
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
-@@ -1416,10 +1519,10 @@
- int vdd_bit = -1;
- u8 ctrl;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD) {
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
- mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
- return;
-@@ -1446,9 +1549,9 @@
- vdd_bit = sdhci_set_power(host, ios->vdd);
-
- if (host->vmmc && vdd_bit != -1) {
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- }
-
- if (host->ops->platform_send_init_74_clocks)
-@@ -1487,7 +1590,7 @@
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
-
-- if (host->version >= SDHCI_SPEC_300) {
-+ if (host->version >= SDHCI_SPEC_300 && !(host->ops->uhs_broken)) {
- u16 clk, ctrl_2;
-
- /* In case of UHS-I modes, set High Speed Enable */
-@@ -1585,7 +1688,7 @@
- sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-@@ -1633,7 +1736,7 @@
- unsigned long flags;
- int is_readonly;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD)
- is_readonly = 0;
-@@ -1643,7 +1746,7 @@
- is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
- & SDHCI_WRITE_PROTECT);
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- /* This quirk needs to be replaced by a callback-function later */
- return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
-@@ -1716,9 +1819,9 @@
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- sdhci_enable_sdio_irq_nolock(host, enable);
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
-@@ -2066,7 +2169,7 @@
- if (host->ops->card_event)
- host->ops->card_event(host);
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- /* Check host->mrq first in case we are runtime suspended */
- if (host->mrq && !sdhci_do_get_cd(host)) {
-@@ -2082,7 +2185,7 @@
- tasklet_schedule(&host->finish_tasklet);
- }
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static const struct mmc_host_ops sdhci_ops = {
-@@ -2121,14 +2224,14 @@
-
- host = (struct sdhci_host*)param;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- /*
- * If this tasklet gets rescheduled while running, it will
- * be run again afterwards but without any active request.
- */
- if (!host->mrq) {
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- return;
- }
-
-@@ -2166,7 +2269,7 @@
- #endif
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- mmc_request_done(host->mmc, mrq);
- sdhci_runtime_pm_put(host);
-@@ -2179,11 +2282,11 @@
-
- host = (struct sdhci_host*)data;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- if (host->mrq) {
- pr_err("%s: Timeout waiting for hardware "
-- "interrupt.\n", mmc_hostname(host->mmc));
-+ "interrupt - cmd%d.\n", mmc_hostname(host->mmc), host->last_cmdop);
- sdhci_dumpregs(host);
-
- if (host->data) {
-@@ -2200,7 +2303,7 @@
- }
-
- mmiowb();
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- static void sdhci_tuning_timer(unsigned long data)
-@@ -2210,11 +2313,11 @@
-
- host = (struct sdhci_host *)data;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- host->flags |= SDHCI_NEEDS_RETUNING;
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- /*****************************************************************************\
-@@ -2228,10 +2331,13 @@
- BUG_ON(intmask == 0);
-
- if (!host->cmd) {
-+ if (!(host->ops->extra_ints)) {
- pr_err("%s: Got command interrupt 0x%08x even "
- "though no command operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_dumpregs(host);
-+ } else
-+ DBG("cmd irq 0x%08x cmd complete\n", (unsigned)intmask);
- return;
- }
-
-@@ -2301,6 +2407,19 @@
- static void sdhci_show_adma_error(struct sdhci_host *host) { }
- #endif
-
-+static void sdhci_data_end(struct sdhci_host *host)
-+{
-+ if (host->cmd) {
-+ /*
-+ * Data managed to finish before the
-+ * command completed. Make sure we do
-+ * things in the proper order.
-+ */
-+ host->data_early = 1;
-+ } else
-+ sdhci_finish_data(host);
-+}
-+
- static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
- {
- u32 command;
-@@ -2330,23 +2449,39 @@
- }
- }
-
-+ if (!(host->ops->extra_ints)) {
- pr_err("%s: Got data interrupt 0x%08x even "
- "though no data operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_dumpregs(host);
-+ } else
-+ DBG("data irq 0x%08x but no data\n", (unsigned)intmask);
-
- return;
- }
-
- if (intmask & SDHCI_INT_DATA_TIMEOUT)
- host->data->error = -ETIMEDOUT;
-- else if (intmask & SDHCI_INT_DATA_END_BIT)
-+ else if (intmask & SDHCI_INT_DATA_END_BIT) {
-+ DBG("end error in cmd %d\n", host->last_cmdop);
-+ if (host->ops->spurious_crc_acmd51 &&
-+ host->last_cmdop == -SD_APP_SEND_SCR) {
-+ DBG("ignoring spurious data_end_bit error\n");
-+ intmask = SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END;
-+ } else
- host->data->error = -EILSEQ;
-- else if ((intmask & SDHCI_INT_DATA_CRC) &&
-+ } else if ((intmask & SDHCI_INT_DATA_CRC) &&
- SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
-- != MMC_BUS_TEST_R)
-+ != MMC_BUS_TEST_R) {
-+ DBG("crc error in cmd %d\n", host->last_cmdop);
-+ if (host->ops->spurious_crc_acmd51 &&
-+ host->last_cmdop == -SD_APP_SEND_SCR) {
-+ DBG("ignoring spurious data_crc_bit error\n");
-+ intmask = SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END;
-+ } else {
- host->data->error = -EILSEQ;
-- else if (intmask & SDHCI_INT_ADMA_ERROR) {
-+ }
-+ } else if (intmask & SDHCI_INT_ADMA_ERROR) {
- pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
- sdhci_show_adma_error(host);
- host->data->error = -EIO;
-@@ -2354,11 +2489,18 @@
- host->ops->adma_workaround(host, intmask);
- }
-
-- if (host->data->error)
-+ if (host->data->error) {
-+ DBG("finish request early on error %d\n", host->data->error);
- sdhci_finish_data(host);
-- else {
-- if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
-- sdhci_transfer_pio(host);
-+ } else {
-+ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) {
-+ if (host->flags & SDHCI_REQ_USE_DMA) {
-+ /* possible only in PLATDMA mode */
-+ sdhci_platdma_avail(host, &intmask,
-+ &sdhci_data_end);
-+ } else
-+ sdhci_transfer_pio(host, intmask);
-+ }
-
- /*
- * We currently don't do anything fancy with DMA
-@@ -2387,18 +2529,8 @@
- sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
- }
-
-- if (intmask & SDHCI_INT_DATA_END) {
-- if (host->cmd) {
-- /*
-- * Data managed to finish before the
-- * command completed. Make sure we do
-- * things in the proper order.
-- */
-- host->data_early = 1;
-- } else {
-- sdhci_finish_data(host);
-- }
-- }
-+ if (intmask & SDHCI_INT_DATA_END)
-+ sdhci_data_end(host);
- }
- }
-
-@@ -2409,10 +2541,10 @@
- u32 intmask, unexpected = 0;
- int cardint = 0, max_loops = 16;
-
-- spin_lock(&host->lock);
-+ sdhci_spin_lock(host);
-
- if (host->runtime_suspended) {
-- spin_unlock(&host->lock);
-+ sdhci_spin_unlock(host);
- pr_warning("%s: got irq while runtime suspended\n",
- mmc_hostname(host->mmc));
- return IRQ_HANDLED;
-@@ -2454,6 +2586,22 @@
- tasklet_schedule(&host->card_tasklet);
- }
-
-+ if (intmask & SDHCI_INT_ERROR_MASK & ~SDHCI_INT_ERROR)
-+ DBG("controller reports error 0x%x -"
-+ "%s%s%s%s%s%s%s%s%s%s",
-+ intmask,
-+ intmask & SDHCI_INT_TIMEOUT? " timeout": "",
-+ intmask & SDHCI_INT_CRC ? " crc": "",
-+ intmask & SDHCI_INT_END_BIT? " endbit": "",
-+ intmask & SDHCI_INT_INDEX? " index": "",
-+ intmask & SDHCI_INT_DATA_TIMEOUT? " data_timeout": "",
-+ intmask & SDHCI_INT_DATA_CRC? " data_crc": "",
-+ intmask & SDHCI_INT_DATA_END_BIT? " data_endbit": "",
-+ intmask & SDHCI_INT_BUS_POWER? " buspower": "",
-+ intmask & SDHCI_INT_ACMD12ERR? " acmd12": "",
-+ intmask & SDHCI_INT_ADMA_ERROR? " adma": ""
-+ );
-+
- if (intmask & SDHCI_INT_CMD_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
- SDHCI_INT_STATUS);
-@@ -2468,7 +2616,13 @@
-
- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
-
-- intmask &= ~SDHCI_INT_ERROR;
-+ if (intmask & SDHCI_INT_ERROR_MASK) {
-+ /* collect any uncovered errors */
-+ sdhci_writel(host, intmask & SDHCI_INT_ERROR_MASK,
-+ SDHCI_INT_STATUS);
-+ }
-+
-+ intmask &= ~SDHCI_INT_ERROR_MASK;
-
- if (intmask & SDHCI_INT_BUS_POWER) {
- pr_err("%s: Card is consuming too much power!\n",
-@@ -2494,7 +2648,7 @@
- if (intmask && --max_loops)
- goto again;
- out:
-- spin_unlock(&host->lock);
-+ sdhci_spin_unlock(host);
-
- if (unexpected) {
- pr_err("%s: Unexpected interrupt 0x%08x.\n",
-@@ -2588,7 +2742,8 @@
- {
- int ret;
-
-- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA |
-+ SDHCI_USE_PLATDMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-@@ -2671,15 +2826,15 @@
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- synchronize_irq(host->irq);
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- host->runtime_suspended = true;
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- return ret;
- }
-@@ -2705,16 +2860,16 @@
- sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
- if ((host_flags & SDHCI_PV_ENABLED) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
- sdhci_enable_preset_value(host, true);
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- /* Set the re-tuning expiration flag */
- if (host->flags & SDHCI_USING_RETUNING_TIMER)
- host->flags |= SDHCI_NEEDS_RETUNING;
-
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- host->runtime_suspended = false;
-
-@@ -2725,7 +2880,7 @@
- /* Enable Card Detection */
- sdhci_enable_card_detection(host);
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
-
- return ret;
- }
-@@ -2820,14 +2975,16 @@
- host->flags &= ~SDHCI_USE_ADMA;
- }
-
-- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-+ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA |
-+ SDHCI_USE_PLATDMA)) {
- if (host->ops->enable_dma) {
- if (host->ops->enable_dma(host)) {
- pr_warning("%s: No suitable DMA "
- "available. Falling back to PIO.\n",
- mmc_hostname(mmc));
- host->flags &=
-- ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
-+ ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA |
-+ SDHCI_USE_PLATDMA);
- }
- }
- }
-@@ -3119,6 +3276,12 @@
- SDHCI_MAX_CURRENT_MULTIPLIER;
- }
-
-+ if(host->ops->voltage_broken) {
-+ ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
-+ // Cannot support UHS modes if we are stuck at 3.3V;
-+ mmc->caps &= ~(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50);
-+ }
-+
- mmc->ocr_avail = ocr_avail;
- mmc->ocr_avail_sdio = ocr_avail;
- if (host->ocr_avail_sdio)
-@@ -3213,7 +3376,7 @@
- host->tuning_timer.function = sdhci_tuning_timer;
- }
-
-- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-+ ret = request_irq(host->irq, sdhci_irq, 0,//IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret) {
- pr_err("%s: Failed to request IRQ %d: %d\n",
-@@ -3249,6 +3412,7 @@
-
- pr_info("%s: SDHCI controller on %s [%s] using %s\n",
- mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
-+ (host->flags & SDHCI_USE_PLATDMA) ? "platform's DMA" :
- (host->flags & SDHCI_USE_ADMA) ? "ADMA" :
- (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
-
-@@ -3276,7 +3440,7 @@
- unsigned long flags;
-
- if (dead) {
-- spin_lock_irqsave(&host->lock, flags);
-+ sdhci_spin_lock_irqsave(host, &flags);
-
- host->flags |= SDHCI_DEVICE_DEAD;
-
-@@ -3288,7 +3452,7 @@
- tasklet_schedule(&host->finish_tasklet);
- }
-
-- spin_unlock_irqrestore(&host->lock, flags);
-+ sdhci_spin_unlock_irqrestore(host, flags);
- }
-
- sdhci_disable_card_detection(host);
-diff -Nur linux-3.11.10.orig/drivers/mmc/host/sdhci.h linux-3.11.10/drivers/mmc/host/sdhci.h
---- linux-3.11.10.orig/drivers/mmc/host/sdhci.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/mmc/host/sdhci.h 2014-02-07 19:57:28.000000000 +0100
-@@ -289,6 +289,20 @@
- void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
- void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
- int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
-+
-+ int (*pdma_able)(struct sdhci_host *host,
-+ struct mmc_data *data);
-+ void (*pdma_avail)(struct sdhci_host *host,
-+ unsigned int *ref_intmask,
-+ void(*complete)(struct sdhci_host *));
-+ void (*pdma_reset)(struct sdhci_host *host,
-+ struct mmc_data *data);
-+ unsigned int (*extra_ints)(struct sdhci_host *host);
-+ unsigned int (*spurious_crc_acmd51)(struct sdhci_host *host);
-+ unsigned int (*voltage_broken)(struct sdhci_host *host);
-+ unsigned int (*uhs_broken)(struct sdhci_host *host);
-+ unsigned int (*missing_status)(struct sdhci_host *host);
-+
- void (*hw_reset)(struct sdhci_host *host);
- void (*platform_suspend)(struct sdhci_host *host);
- void (*platform_resume)(struct sdhci_host *host);
-@@ -400,9 +414,38 @@
- extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
- #endif
-
-+static inline int /*bool*/
-+sdhci_platdma_dmaable(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ if (host->ops->pdma_able)
-+ return host->ops->pdma_able(host, data);
-+ else
-+ return 1;
-+}
-+static inline void
-+sdhci_platdma_avail(struct sdhci_host *host, unsigned int *ref_intmask,
-+ void(*completion_callback)(struct sdhci_host *))
-+{
-+ if (host->ops->pdma_avail)
-+ host->ops->pdma_avail(host, ref_intmask, completion_callback);
-+}
-+
-+static inline void
-+sdhci_platdma_reset(struct sdhci_host *host, struct mmc_data *data)
-+{
-+ if (host->ops->pdma_reset)
-+ host->ops->pdma_reset(host, data);
-+}
-+
- #ifdef CONFIG_PM_RUNTIME
- extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
- extern int sdhci_runtime_resume_host(struct sdhci_host *host);
- #endif
-
-+extern void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags);
-+extern void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags);
-+extern void sdhci_spin_lock(struct sdhci_host *host);
-+extern void sdhci_spin_unlock(struct sdhci_host *host);
-+
-+
- #endif /* __SDHCI_HW_H */
-diff -Nur linux-3.11.10.orig/drivers/net/usb/smsc95xx.c linux-3.11.10/drivers/net/usb/smsc95xx.c
---- linux-3.11.10.orig/drivers/net/usb/smsc95xx.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/net/usb/smsc95xx.c 2014-02-07 19:57:28.000000000 +0100
-@@ -61,6 +61,7 @@
- #define SUSPEND_SUSPEND3 (0x08)
- #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
- SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
-+#define MAC_ADDR_LEN (6)
-
- struct smsc95xx_priv {
- u32 mac_cr;
-@@ -76,6 +77,10 @@
- module_param(turbo_mode, bool, 0644);
- MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
-
-+static char *macaddr = ":";
-+module_param(macaddr, charp, 0);
-+MODULE_PARM_DESC(macaddr, "MAC address");
-+
- static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
- u32 *data, int in_pm)
- {
-@@ -765,8 +770,59 @@
- return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
- }
-
-+/* Check the macaddr module parameter for a MAC address */
-+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
-+{
-+ int i, j, got_num, num;
-+ u8 mtbl[MAC_ADDR_LEN];
-+
-+ if (macaddr[0] == ':')
-+ return 0;
-+
-+ i = 0;
-+ j = 0;
-+ num = 0;
-+ got_num = 0;
-+ while (j < MAC_ADDR_LEN) {
-+ if (macaddr[i] && macaddr[i] != ':') {
-+ got_num++;
-+ if ('0' <= macaddr[i] && macaddr[i] <= '9')
-+ num = num * 16 + macaddr[i] - '0';
-+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
-+ num = num * 16 + 10 + macaddr[i] - 'A';
-+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
-+ num = num * 16 + 10 + macaddr[i] - 'a';
-+ else
-+ break;
-+ i++;
-+ } else if (got_num == 2) {
-+ mtbl[j++] = (u8) num;
-+ num = 0;
-+ got_num = 0;
-+ i++;
-+ } else {
-+ break;
-+ }
-+ }
-+
-+ if (j == MAC_ADDR_LEN) {
-+ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
-+ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
-+ mtbl[3], mtbl[4], mtbl[5]);
-+ for (i = 0; i < MAC_ADDR_LEN; i++)
-+ dev_mac[i] = mtbl[i];
-+ return 1;
-+ } else {
-+ return 0;
-+ }
-+}
-+
- static void smsc95xx_init_mac_address(struct usbnet *dev)
- {
-+ /* Check module parameters */
-+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
-+ return;
-+
- /* try reading mac address from EEPROM */
- if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
- dev->net->dev_addr) == 0) {
-diff -Nur linux-3.11.10.orig/drivers/net/wireless/ath/ath9k/hif_usb.c linux-3.11.10/drivers/net/wireless/ath/ath9k/hif_usb.c
---- linux-3.11.10.orig/drivers/net/wireless/ath/ath9k/hif_usb.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/net/wireless/ath/ath9k/hif_usb.c 2014-02-07 19:57:28.000000000 +0100
-@@ -37,9 +37,11 @@
- { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */
- { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
- { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
-+ { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */
- { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
- { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */
- { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
-+ { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
-
- { USB_DEVICE(0x0cf3, 0x7015),
- .driver_info = AR9287_USB }, /* Atheros */
-diff -Nur linux-3.11.10.orig/drivers/net/wireless/rt2x00/rt2800.h linux-3.11.10/drivers/net/wireless/rt2x00/rt2800.h
---- linux-3.11.10.orig/drivers/net/wireless/rt2x00/rt2800.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/net/wireless/rt2x00/rt2800.h 2014-02-07 19:57:28.000000000 +0100
-@@ -70,6 +70,7 @@
- #define RF3322 0x000c
- #define RF3053 0x000d
- #define RF5592 0x000f
-+#define RF3070 0x3070
- #define RF3290 0x3290
- #define RF5360 0x5360
- #define RF5370 0x5370
-diff -Nur linux-3.11.10.orig/drivers/net/wireless/rt2x00/rt2800lib.c linux-3.11.10/drivers/net/wireless/rt2x00/rt2800lib.c
---- linux-3.11.10.orig/drivers/net/wireless/rt2x00/rt2800lib.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/net/wireless/rt2x00/rt2800lib.c 2014-02-07 19:57:28.000000000 +0100
-@@ -2599,6 +2599,7 @@
- break;
- case RF5360:
- case RF5370:
-+ case RF3070:
- case RF5372:
- case RF5390:
- case RF5392:
-@@ -2615,6 +2616,7 @@
- rt2x00_rf(rt2x00dev, RF3322) ||
- rt2x00_rf(rt2x00dev, RF5360) ||
- rt2x00_rf(rt2x00dev, RF5370) ||
-+ rt2x00_rf(rt2x00dev, RF3070) ||
- rt2x00_rf(rt2x00dev, RF5372) ||
- rt2x00_rf(rt2x00dev, RF5390) ||
- rt2x00_rf(rt2x00dev, RF5392)) {
-@@ -3229,6 +3231,7 @@
- case RF3290:
- case RF5360:
- case RF5370:
-+ case RF3070:
- case RF5372:
- case RF5390:
- case RF5392:
-@@ -5747,6 +5750,7 @@
- case RF3322:
- case RF5360:
- case RF5370:
-+ case RF3070:
- case RF5372:
- case RF5390:
- case RF5392:
-@@ -6202,6 +6206,7 @@
- rt2x00_rf(rt2x00dev, RF3322) ||
- rt2x00_rf(rt2x00dev, RF5360) ||
- rt2x00_rf(rt2x00dev, RF5370) ||
-+ rt2x00_rf(rt2x00dev, RF3070) ||
- rt2x00_rf(rt2x00dev, RF5372) ||
- rt2x00_rf(rt2x00dev, RF5390) ||
- rt2x00_rf(rt2x00dev, RF5392)) {
-@@ -6304,6 +6309,7 @@
- case RF3290:
- case RF5360:
- case RF5370:
-+ case RF3070:
- case RF5372:
- case RF5390:
- case RF5392:
-diff -Nur linux-3.11.10.orig/drivers/net/wireless/rt2x00/rt2800lib.c.orig linux-3.11.10/drivers/net/wireless/rt2x00/rt2800lib.c.orig
---- linux-3.11.10.orig/drivers/net/wireless/rt2x00/rt2800lib.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/net/wireless/rt2x00/rt2800lib.c.orig 2013-11-29 19:42:37.000000000 +0100
-@@ -0,0 +1,6652 @@
-+/*
-+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
-+ Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
-+ Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
-+ Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
-+
-+ Based on the original rt2800pci.c and rt2800usb.c.
-+ Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
-+ Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
-+ Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
-+ Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
-+ Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
-+ Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
-+ <http://rt2x00.serialmonkey.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the
-+ Free Software Foundation, Inc.,
-+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+/*
-+ Module: rt2800lib
-+ Abstract: rt2800 generic device routines.
-+ */
-+
-+#include <linux/crc-ccitt.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+
-+#include "rt2x00.h"
-+#include "rt2800lib.h"
-+#include "rt2800.h"
-+
-+/*
-+ * Register access.
-+ * All access to the CSR registers will go through the methods
-+ * rt2800_register_read and rt2800_register_write.
-+ * BBP and RF register require indirect register access,
-+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
-+ * These indirect registers work with busy bits,
-+ * and we will try maximal REGISTER_BUSY_COUNT times to access
-+ * the register while taking a REGISTER_BUSY_DELAY us delay
-+ * between each attampt. When the busy bit is still set at that time,
-+ * the access attempt is considered to have failed,
-+ * and we will print an error.
-+ * The _lock versions must be used if you already hold the csr_mutex
-+ */
-+#define WAIT_FOR_BBP(__dev, __reg) \
-+ rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg))
-+#define WAIT_FOR_RFCSR(__dev, __reg) \
-+ rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg))
-+#define WAIT_FOR_RF(__dev, __reg) \
-+ rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg))
-+#define WAIT_FOR_MCU(__dev, __reg) \
-+ rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \
-+ H2M_MAILBOX_CSR_OWNER, (__reg))
-+
-+static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
-+{
-+ /* check for rt2872 on SoC */
-+ if (!rt2x00_is_soc(rt2x00dev) ||
-+ !rt2x00_rt(rt2x00dev, RT2872))
-+ return false;
-+
-+ /* we know for sure that these rf chipsets are used on rt305x boards */
-+ if (rt2x00_rf(rt2x00dev, RF3020) ||
-+ rt2x00_rf(rt2x00dev, RF3021) ||
-+ rt2x00_rf(rt2x00dev, RF3022))
-+ return true;
-+
-+ rt2x00_warn(rt2x00dev, "Unknown RF chipset on rt305x\n");
-+ return false;
-+}
-+
-+static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int word, const u8 value)
-+{
-+ u32 reg;
-+
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ /*
-+ * Wait until the BBP becomes available, afterwards we
-+ * can safely write the new data into the register.
-+ */
-+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
-+ reg = 0;
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_VALUE, value);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
-+
-+ rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
-+ }
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+
-+static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int word, u8 *value)
-+{
-+ u32 reg;
-+
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ /*
-+ * Wait until the BBP becomes available, afterwards we
-+ * can safely write the read request into the register.
-+ * After the data has been written, we wait until hardware
-+ * returns the correct value, if at any time the register
-+ * doesn't become available in time, reg will be 0xffffffff
-+ * which means we return 0xff to the caller.
-+ */
-+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
-+ reg = 0;
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
-+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
-+
-+ rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
-+
-+ WAIT_FOR_BBP(rt2x00dev, &reg);
-+ }
-+
-+ *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE);
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+
-+static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int word, const u8 value)
-+{
-+ u32 reg;
-+
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ /*
-+ * Wait until the RFCSR becomes available, afterwards we
-+ * can safely write the new data into the register.
-+ */
-+ if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
-+ reg = 0;
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_DATA, value);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 1);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
-+
-+ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
-+ }
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+
-+static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int word, u8 *value)
-+{
-+ u32 reg;
-+
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ /*
-+ * Wait until the RFCSR becomes available, afterwards we
-+ * can safely write the read request into the register.
-+ * After the data has been written, we wait until hardware
-+ * returns the correct value, if at any time the register
-+ * doesn't become available in time, reg will be 0xffffffff
-+ * which means we return 0xff to the caller.
-+ */
-+ if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
-+ reg = 0;
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 0);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
-+
-+ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
-+
-+ WAIT_FOR_RFCSR(rt2x00dev, &reg);
-+ }
-+
-+ *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+
-+static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int word, const u32 value)
-+{
-+ u32 reg;
-+
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ /*
-+ * Wait until the RF becomes available, afterwards we
-+ * can safely write the new data into the register.
-+ */
-+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
-+ reg = 0;
-+ rt2x00_set_field32(&reg, RF_CSR_CFG0_REG_VALUE_BW, value);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG0_STANDBYMODE, 0);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG0_SEL, 0);
-+ rt2x00_set_field32(&reg, RF_CSR_CFG0_BUSY, 1);
-+
-+ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg);
-+ rt2x00_rf_write(rt2x00dev, word, value);
-+ }
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+
-+static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+ int i, count;
-+
-+ rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-+ if (rt2x00_get_field32(reg, WLAN_EN))
-+ return 0;
-+
-+ rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
-+ rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
-+ rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
-+ rt2x00_set_field32(&reg, WLAN_EN, 1);
-+ rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-+
-+ udelay(REGISTER_BUSY_DELAY);
-+
-+ count = 0;
-+ do {
-+ /*
-+ * Check PLL_LD & XTAL_RDY.
-+ */
-+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-+ rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
-+ if (rt2x00_get_field32(reg, PLL_LD) &&
-+ rt2x00_get_field32(reg, XTAL_RDY))
-+ break;
-+ udelay(REGISTER_BUSY_DELAY);
-+ }
-+
-+ if (i >= REGISTER_BUSY_COUNT) {
-+
-+ if (count >= 10)
-+ return -EIO;
-+
-+ rt2800_register_write(rt2x00dev, 0x58, 0x018);
-+ udelay(REGISTER_BUSY_DELAY);
-+ rt2800_register_write(rt2x00dev, 0x58, 0x418);
-+ udelay(REGISTER_BUSY_DELAY);
-+ rt2800_register_write(rt2x00dev, 0x58, 0x618);
-+ udelay(REGISTER_BUSY_DELAY);
-+ count++;
-+ } else {
-+ count = 0;
-+ }
-+
-+ rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-+ rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
-+ rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
-+ rt2x00_set_field32(&reg, WLAN_RESET, 1);
-+ rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-+ udelay(10);
-+ rt2x00_set_field32(&reg, WLAN_RESET, 0);
-+ rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-+ udelay(10);
-+ rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
-+ } while (count != 0);
-+
-+ return 0;
-+}
-+
-+void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
-+ const u8 command, const u8 token,
-+ const u8 arg0, const u8 arg1)
-+{
-+ u32 reg;
-+
-+ /*
-+ * SOC devices don't support MCU requests.
-+ */
-+ if (rt2x00_is_soc(rt2x00dev))
-+ return;
-+
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ /*
-+ * Wait until the MCU becomes available, afterwards we
-+ * can safely write the new data into the register.
-+ */
-+ if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
-+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
-+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
-+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
-+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
-+ rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg);
-+
-+ reg = 0;
-+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
-+ rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg);
-+ }
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_mcu_request);
-+
-+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev)
-+{
-+ unsigned int i = 0;
-+ u32 reg;
-+
-+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-+ if (reg && reg != ~0)
-+ return 0;
-+ msleep(1);
-+ }
-+
-+ rt2x00_err(rt2x00dev, "Unstable hardware\n");
-+ return -EBUSY;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready);
-+
-+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
-+{
-+ unsigned int i;
-+ u32 reg;
-+
-+ /*
-+ * Some devices are really slow to respond here. Wait a whole second
-+ * before timing out.
-+ */
-+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-+ if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
-+ !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
-+ return 0;
-+
-+ msleep(10);
-+ }
-+
-+ rt2x00_err(rt2x00dev, "WPDMA TX/RX busy [0x%08x]\n", reg);
-+ return -EACCES;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
-+
-+void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+
-+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-+ rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_disable_wpdma);
-+
-+static bool rt2800_check_firmware_crc(const u8 *data, const size_t len)
-+{
-+ u16 fw_crc;
-+ u16 crc;
-+
-+ /*
-+ * The last 2 bytes in the firmware array are the crc checksum itself,
-+ * this means that we should never pass those 2 bytes to the crc
-+ * algorithm.
-+ */
-+ fw_crc = (data[len - 2] << 8 | data[len - 1]);
-+
-+ /*
-+ * Use the crc ccitt algorithm.
-+ * This will return the same value as the legacy driver which
-+ * used bit ordering reversion on the both the firmware bytes
-+ * before input input as well as on the final output.
-+ * Obviously using crc ccitt directly is much more efficient.
-+ */
-+ crc = crc_ccitt(~0, data, len - 2);
-+
-+ /*
-+ * There is a small difference between the crc-itu-t + bitrev and
-+ * the crc-ccitt crc calculation. In the latter method the 2 bytes
-+ * will be swapped, use swab16 to convert the crc to the correct
-+ * value.
-+ */
-+ crc = swab16(crc);
-+
-+ return fw_crc == crc;
-+}
-+
-+int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
-+ const u8 *data, const size_t len)
-+{
-+ size_t offset = 0;
-+ size_t fw_len;
-+ bool multiple;
-+
-+ /*
-+ * PCI(e) & SOC devices require firmware with a length
-+ * of 8kb. USB devices require firmware files with a length
-+ * of 4kb. Certain USB chipsets however require different firmware,
-+ * which Ralink only provides attached to the original firmware
-+ * file. Thus for USB devices, firmware files have a length
-+ * which is a multiple of 4kb. The firmware for rt3290 chip also
-+ * have a length which is a multiple of 4kb.
-+ */
-+ if (rt2x00_is_usb(rt2x00dev) || rt2x00_rt(rt2x00dev, RT3290))
-+ fw_len = 4096;
-+ else
-+ fw_len = 8192;
-+
-+ multiple = true;
-+ /*
-+ * Validate the firmware length
-+ */
-+ if (len != fw_len && (!multiple || (len % fw_len) != 0))
-+ return FW_BAD_LENGTH;
-+
-+ /*
-+ * Check if the chipset requires one of the upper parts
-+ * of the firmware.
-+ */
-+ if (rt2x00_is_usb(rt2x00dev) &&
-+ !rt2x00_rt(rt2x00dev, RT2860) &&
-+ !rt2x00_rt(rt2x00dev, RT2872) &&
-+ !rt2x00_rt(rt2x00dev, RT3070) &&
-+ ((len / fw_len) == 1))
-+ return FW_BAD_VERSION;
-+
-+ /*
-+ * 8kb firmware files must be checked as if it were
-+ * 2 separate firmware files.
-+ */
-+ while (offset < len) {
-+ if (!rt2800_check_firmware_crc(data + offset, fw_len))
-+ return FW_BAD_CRC;
-+
-+ offset += fw_len;
-+ }
-+
-+ return FW_OK;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_check_firmware);
-+
-+int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
-+ const u8 *data, const size_t len)
-+{
-+ unsigned int i;
-+ u32 reg;
-+ int retval;
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290)) {
-+ retval = rt2800_enable_wlan_rt3290(rt2x00dev);
-+ if (retval)
-+ return -EBUSY;
-+ }
-+
-+ /*
-+ * If driver doesn't wake up firmware here,
-+ * rt2800_load_firmware will hang forever when interface is up again.
-+ */
-+ rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
-+
-+ /*
-+ * Wait for stable hardware.
-+ */
-+ if (rt2800_wait_csr_ready(rt2x00dev))
-+ return -EBUSY;
-+
-+ if (rt2x00_is_pci(rt2x00dev)) {
-+ if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3572) ||
-+ rt2x00_rt(rt2x00dev, RT5390) ||
-+ rt2x00_rt(rt2x00dev, RT5392)) {
-+ rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
-+ rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
-+ rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
-+ rt2800_register_write(rt2x00dev, AUX_CTRL, reg);
-+ }
-+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
-+ }
-+
-+ rt2800_disable_wpdma(rt2x00dev);
-+
-+ /*
-+ * Write firmware to the device.
-+ */
-+ rt2800_drv_write_firmware(rt2x00dev, data, len);
-+
-+ /*
-+ * Wait for device to stabilize.
-+ */
-+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-+ rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
-+ if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
-+ break;
-+ msleep(1);
-+ }
-+
-+ if (i == REGISTER_BUSY_COUNT) {
-+ rt2x00_err(rt2x00dev, "PBF system register not ready\n");
-+ return -EBUSY;
-+ }
-+
-+ /*
-+ * Disable DMA, will be reenabled later when enabling
-+ * the radio.
-+ */
-+ rt2800_disable_wpdma(rt2x00dev);
-+
-+ /*
-+ * Initialize firmware.
-+ */
-+ rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
-+ rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
-+ if (rt2x00_is_usb(rt2x00dev)) {
-+ rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
-+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-+ }
-+ msleep(1);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_load_firmware);
-+
-+void rt2800_write_tx_data(struct queue_entry *entry,
-+ struct txentry_desc *txdesc)
-+{
-+ __le32 *txwi = rt2800_drv_get_txwi(entry);
-+ u32 word;
-+ int i;
-+
-+ /*
-+ * Initialize TX Info descriptor
-+ */
-+ rt2x00_desc_read(txwi, 0, &word);
-+ rt2x00_set_field32(&word, TXWI_W0_FRAG,
-+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W0_MIMO_PS,
-+ test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
-+ rt2x00_set_field32(&word, TXWI_W0_TS,
-+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W0_AMPDU,
-+ test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY,
-+ txdesc->u.ht.mpdu_density);
-+ rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->u.ht.txop);
-+ rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->u.ht.mcs);
-+ rt2x00_set_field32(&word, TXWI_W0_BW,
-+ test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
-+ test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->u.ht.stbc);
-+ rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
-+ rt2x00_desc_write(txwi, 0, word);
-+
-+ rt2x00_desc_read(txwi, 1, &word);
-+ rt2x00_set_field32(&word, TXWI_W1_ACK,
-+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W1_NSEQ,
-+ test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
-+ rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size);
-+ rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
-+ test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
-+ txdesc->key_idx : txdesc->u.ht.wcid);
-+ rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
-+ txdesc->length);
-+ rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid);
-+ rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1);
-+ rt2x00_desc_write(txwi, 1, word);
-+
-+ /*
-+ * Always write 0 to IV/EIV fields (word 2 and 3), hardware will insert
-+ * the IV from the IVEIV register when TXD_W3_WIV is set to 0.
-+ * When TXD_W3_WIV is set to 1 it will use the IV data
-+ * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
-+ * crypto entry in the registers should be used to encrypt the frame.
-+ *
-+ * Nulify all remaining words as well, we don't know how to program them.
-+ */
-+ for (i = 2; i < entry->queue->winfo_size / sizeof(__le32); i++)
-+ _rt2x00_desc_write(txwi, i, 0);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_write_tx_data);
-+
-+static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2)
-+{
-+ s8 rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
-+ s8 rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
-+ s8 rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
-+ u16 eeprom;
-+ u8 offset0;
-+ u8 offset1;
-+ u8 offset2;
-+
-+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
-+ offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
-+ offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
-+ offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
-+ } else {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
-+ offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
-+ offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
-+ offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
-+ }
-+
-+ /*
-+ * Convert the value from the descriptor into the RSSI value
-+ * If the value in the descriptor is 0, it is considered invalid
-+ * and the default (extremely low) rssi value is assumed
-+ */
-+ rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
-+ rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
-+ rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
-+
-+ /*
-+ * mac80211 only accepts a single RSSI value. Calculating the
-+ * average doesn't deliver a fair answer either since -60:-60 would
-+ * be considered equally good as -50:-70 while the second is the one
-+ * which gives less energy...
-+ */
-+ rssi0 = max(rssi0, rssi1);
-+ return (int)max(rssi0, rssi2);
-+}
-+
-+void rt2800_process_rxwi(struct queue_entry *entry,
-+ struct rxdone_entry_desc *rxdesc)
-+{
-+ __le32 *rxwi = (__le32 *) entry->skb->data;
-+ u32 word;
-+
-+ rt2x00_desc_read(rxwi, 0, &word);
-+
-+ rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF);
-+ rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
-+
-+ rt2x00_desc_read(rxwi, 1, &word);
-+
-+ if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI))
-+ rxdesc->flags |= RX_FLAG_SHORT_GI;
-+
-+ if (rt2x00_get_field32(word, RXWI_W1_BW))
-+ rxdesc->flags |= RX_FLAG_40MHZ;
-+
-+ /*
-+ * Detect RX rate, always use MCS as signal type.
-+ */
-+ rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
-+ rxdesc->signal = rt2x00_get_field32(word, RXWI_W1_MCS);
-+ rxdesc->rate_mode = rt2x00_get_field32(word, RXWI_W1_PHYMODE);
-+
-+ /*
-+ * Mask of 0x8 bit to remove the short preamble flag.
-+ */
-+ if (rxdesc->rate_mode == RATE_MODE_CCK)
-+ rxdesc->signal &= ~0x8;
-+
-+ rt2x00_desc_read(rxwi, 2, &word);
-+
-+ /*
-+ * Convert descriptor AGC value to RSSI value.
-+ */
-+ rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
-+ /*
-+ * Remove RXWI descriptor from start of the buffer.
-+ */
-+ skb_pull(entry->skb, entry->queue->winfo_size);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
-+
-+void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi)
-+{
-+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-+ struct txdone_entry_desc txdesc;
-+ u32 word;
-+ u16 mcs, real_mcs;
-+ int aggr, ampdu;
-+
-+ /*
-+ * Obtain the status about this packet.
-+ */
-+ txdesc.flags = 0;
-+ rt2x00_desc_read(txwi, 0, &word);
-+
-+ mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
-+ ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU);
-+
-+ real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS);
-+ aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE);
-+
-+ /*
-+ * If a frame was meant to be sent as a single non-aggregated MPDU
-+ * but ended up in an aggregate the used tx rate doesn't correlate
-+ * with the one specified in the TXWI as the whole aggregate is sent
-+ * with the same rate.
-+ *
-+ * For example: two frames are sent to rt2x00, the first one sets
-+ * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0
-+ * and requests MCS15. If the hw aggregates both frames into one
-+ * AMDPU the tx status for both frames will contain MCS7 although
-+ * the frame was sent successfully.
-+ *
-+ * Hence, replace the requested rate with the real tx rate to not
-+ * confuse the rate control algortihm by providing clearly wrong
-+ * data.
-+ */
-+ if (unlikely(aggr == 1 && ampdu == 0 && real_mcs != mcs)) {
-+ skbdesc->tx_rate_idx = real_mcs;
-+ mcs = real_mcs;
-+ }
-+
-+ if (aggr == 1 || ampdu == 1)
-+ __set_bit(TXDONE_AMPDU, &txdesc.flags);
-+
-+ /*
-+ * Ralink has a retry mechanism using a global fallback
-+ * table. We setup this fallback table to try the immediate
-+ * lower rate for all rates. In the TX_STA_FIFO, the MCS field
-+ * always contains the MCS used for the last transmission, be
-+ * it successful or not.
-+ */
-+ if (rt2x00_get_field32(status, TX_STA_FIFO_TX_SUCCESS)) {
-+ /*
-+ * Transmission succeeded. The number of retries is
-+ * mcs - real_mcs
-+ */
-+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
-+ txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
-+ } else {
-+ /*
-+ * Transmission failed. The number of retries is
-+ * always 7 in this case (for a total number of 8
-+ * frames sent).
-+ */
-+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
-+ txdesc.retry = rt2x00dev->long_retry;
-+ }
-+
-+ /*
-+ * the frame was retried at least once
-+ * -> hw used fallback rates
-+ */
-+ if (txdesc.retry)
-+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
-+
-+ rt2x00lib_txdone(entry, &txdesc);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
-+
-+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
-+{
-+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-+ unsigned int beacon_base;
-+ unsigned int padding_len;
-+ u32 orig_reg, reg;
-+ const int txwi_desc_size = entry->queue->winfo_size;
-+
-+ /*
-+ * Disable beaconing while we are reloading the beacon data,
-+ * otherwise we might be sending out invalid data.
-+ */
-+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-+ orig_reg = reg;
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+
-+ /*
-+ * Add space for the TXWI in front of the skb.
-+ */
-+ memset(skb_push(entry->skb, txwi_desc_size), 0, txwi_desc_size);
-+
-+ /*
-+ * Register descriptor details in skb frame descriptor.
-+ */
-+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
-+ skbdesc->desc = entry->skb->data;
-+ skbdesc->desc_len = txwi_desc_size;
-+
-+ /*
-+ * Add the TXWI for the beacon to the skb.
-+ */
-+ rt2800_write_tx_data(entry, txdesc);
-+
-+ /*
-+ * Dump beacon to userspace through debugfs.
-+ */
-+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
-+
-+ /*
-+ * Write entire beacon with TXWI and padding to register.
-+ */
-+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
-+ if (padding_len && skb_pad(entry->skb, padding_len)) {
-+ rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n");
-+ /* skb freed by skb_pad() on failure */
-+ entry->skb = NULL;
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
-+ return;
-+ }
-+
-+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-+ rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
-+ entry->skb->len + padding_len);
-+
-+ /*
-+ * Enable beaconing again.
-+ */
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+
-+ /*
-+ * Clean up beacon skb.
-+ */
-+ dev_kfree_skb_any(entry->skb);
-+ entry->skb = NULL;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_write_beacon);
-+
-+static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
-+ unsigned int beacon_base)
-+{
-+ int i;
-+ const int txwi_desc_size = rt2x00dev->bcn->winfo_size;
-+
-+ /*
-+ * For the Beacon base registers we only need to clear
-+ * the whole TXWI which (when set to 0) will invalidate
-+ * the entire beacon.
-+ */
-+ for (i = 0; i < txwi_desc_size; i += sizeof(__le32))
-+ rt2800_register_write(rt2x00dev, beacon_base + i, 0);
-+}
-+
-+void rt2800_clear_beacon(struct queue_entry *entry)
-+{
-+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-+ u32 reg;
-+
-+ /*
-+ * Disable beaconing while we are reloading the beacon data,
-+ * otherwise we might be sending out invalid data.
-+ */
-+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+
-+ /*
-+ * Clear beacon.
-+ */
-+ rt2800_clear_beacon_register(rt2x00dev,
-+ HW_BEACON_OFFSET(entry->entry_idx));
-+
-+ /*
-+ * Enabled beaconing again.
-+ */
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_clear_beacon);
-+
-+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-+const struct rt2x00debug rt2800_rt2x00debug = {
-+ .owner = THIS_MODULE,
-+ .csr = {
-+ .read = rt2800_register_read,
-+ .write = rt2800_register_write,
-+ .flags = RT2X00DEBUGFS_OFFSET,
-+ .word_base = CSR_REG_BASE,
-+ .word_size = sizeof(u32),
-+ .word_count = CSR_REG_SIZE / sizeof(u32),
-+ },
-+ .eeprom = {
-+ .read = rt2x00_eeprom_read,
-+ .write = rt2x00_eeprom_write,
-+ .word_base = EEPROM_BASE,
-+ .word_size = sizeof(u16),
-+ .word_count = EEPROM_SIZE / sizeof(u16),
-+ },
-+ .bbp = {
-+ .read = rt2800_bbp_read,
-+ .write = rt2800_bbp_write,
-+ .word_base = BBP_BASE,
-+ .word_size = sizeof(u8),
-+ .word_count = BBP_SIZE / sizeof(u8),
-+ },
-+ .rf = {
-+ .read = rt2x00_rf_read,
-+ .write = rt2800_rf_write,
-+ .word_base = RF_BASE,
-+ .word_size = sizeof(u32),
-+ .word_count = RF_SIZE / sizeof(u32),
-+ },
-+ .rfcsr = {
-+ .read = rt2800_rfcsr_read,
-+ .write = rt2800_rfcsr_write,
-+ .word_base = RFCSR_BASE,
-+ .word_size = sizeof(u8),
-+ .word_count = RFCSR_SIZE / sizeof(u8),
-+ },
-+};
-+EXPORT_SYMBOL_GPL(rt2800_rt2x00debug);
-+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-+
-+int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290)) {
-+ rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-+ return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0);
-+ } else {
-+ rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
-+ return rt2x00_get_field32(reg, GPIO_CTRL_VAL2);
-+ }
-+}
-+EXPORT_SYMBOL_GPL(rt2800_rfkill_poll);
-+
-+#ifdef CONFIG_RT2X00_LIB_LEDS
-+static void rt2800_brightness_set(struct led_classdev *led_cdev,
-+ enum led_brightness brightness)
-+{
-+ struct rt2x00_led *led =
-+ container_of(led_cdev, struct rt2x00_led, led_dev);
-+ unsigned int enabled = brightness != LED_OFF;
-+ unsigned int bg_mode =
-+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
-+ unsigned int polarity =
-+ rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
-+ EEPROM_FREQ_LED_POLARITY);
-+ unsigned int ledmode =
-+ rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
-+ EEPROM_FREQ_LED_MODE);
-+ u32 reg;
-+
-+ /* Check for SoC (SOC devices don't support MCU requests) */
-+ if (rt2x00_is_soc(led->rt2x00dev)) {
-+ rt2800_register_read(led->rt2x00dev, LED_CFG, &reg);
-+
-+ /* Set LED Polarity */
-+ rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, polarity);
-+
-+ /* Set LED Mode */
-+ if (led->type == LED_TYPE_RADIO) {
-+ rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE,
-+ enabled ? 3 : 0);
-+ } else if (led->type == LED_TYPE_ASSOC) {
-+ rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE,
-+ enabled ? 3 : 0);
-+ } else if (led->type == LED_TYPE_QUALITY) {
-+ rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE,
-+ enabled ? 3 : 0);
-+ }
-+
-+ rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
-+
-+ } else {
-+ if (led->type == LED_TYPE_RADIO) {
-+ rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
-+ enabled ? 0x20 : 0);
-+ } else if (led->type == LED_TYPE_ASSOC) {
-+ rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
-+ enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
-+ } else if (led->type == LED_TYPE_QUALITY) {
-+ /*
-+ * The brightness is divided into 6 levels (0 - 5),
-+ * The specs tell us the following levels:
-+ * 0, 1 ,3, 7, 15, 31
-+ * to determine the level in a simple way we can simply
-+ * work with bitshifting:
-+ * (1 << level) - 1
-+ */
-+ rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
-+ (1 << brightness / (LED_FULL / 6)) - 1,
-+ polarity);
-+ }
-+ }
-+}
-+
-+static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00_led *led, enum led_type type)
-+{
-+ led->rt2x00dev = rt2x00dev;
-+ led->type = type;
-+ led->led_dev.brightness_set = rt2800_brightness_set;
-+ led->flags = LED_INITIALIZED;
-+}
-+#endif /* CONFIG_RT2X00_LIB_LEDS */
-+
-+/*
-+ * Configuration handlers.
-+ */
-+static void rt2800_config_wcid(struct rt2x00_dev *rt2x00dev,
-+ const u8 *address,
-+ int wcid)
-+{
-+ struct mac_wcid_entry wcid_entry;
-+ u32 offset;
-+
-+ offset = MAC_WCID_ENTRY(wcid);
-+
-+ memset(&wcid_entry, 0xff, sizeof(wcid_entry));
-+ if (address)
-+ memcpy(wcid_entry.mac, address, ETH_ALEN);
-+
-+ rt2800_register_multiwrite(rt2x00dev, offset,
-+ &wcid_entry, sizeof(wcid_entry));
-+}
-+
-+static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid)
-+{
-+ u32 offset;
-+ offset = MAC_WCID_ATTR_ENTRY(wcid);
-+ rt2800_register_write(rt2x00dev, offset, 0);
-+}
-+
-+static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
-+ int wcid, u32 bssidx)
-+{
-+ u32 offset = MAC_WCID_ATTR_ENTRY(wcid);
-+ u32 reg;
-+
-+ /*
-+ * The BSS Idx numbers is split in a main value of 3 bits,
-+ * and a extended field for adding one additional bit to the value.
-+ */
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7));
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
-+ (bssidx & 0x8) >> 3);
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+}
-+
-+static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_crypto *crypto,
-+ struct ieee80211_key_conf *key)
-+{
-+ struct mac_iveiv_entry iveiv_entry;
-+ u32 offset;
-+ u32 reg;
-+
-+ offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
-+
-+ if (crypto->cmd == SET_KEY) {
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
-+ !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
-+ /*
-+ * Both the cipher as the BSS Idx numbers are split in a main
-+ * value of 3 bits, and a extended field for adding one additional
-+ * bit to the value.
-+ */
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
-+ (crypto->cipher & 0x7));
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT,
-+ (crypto->cipher & 0x8) >> 3);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+ } else {
-+ /* Delete the cipher without touching the bssidx */
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB, 0);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER, 0);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0);
-+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+ }
-+
-+ offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
-+
-+ memset(&iveiv_entry, 0, sizeof(iveiv_entry));
-+ if ((crypto->cipher == CIPHER_TKIP) ||
-+ (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
-+ (crypto->cipher == CIPHER_AES))
-+ iveiv_entry.iv[3] |= 0x20;
-+ iveiv_entry.iv[3] |= key->keyidx << 6;
-+ rt2800_register_multiwrite(rt2x00dev, offset,
-+ &iveiv_entry, sizeof(iveiv_entry));
-+}
-+
-+int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_crypto *crypto,
-+ struct ieee80211_key_conf *key)
-+{
-+ struct hw_key_entry key_entry;
-+ struct rt2x00_field32 field;
-+ u32 offset;
-+ u32 reg;
-+
-+ if (crypto->cmd == SET_KEY) {
-+ key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx;
-+
-+ memcpy(key_entry.key, crypto->key,
-+ sizeof(key_entry.key));
-+ memcpy(key_entry.tx_mic, crypto->tx_mic,
-+ sizeof(key_entry.tx_mic));
-+ memcpy(key_entry.rx_mic, crypto->rx_mic,
-+ sizeof(key_entry.rx_mic));
-+
-+ offset = SHARED_KEY_ENTRY(key->hw_key_idx);
-+ rt2800_register_multiwrite(rt2x00dev, offset,
-+ &key_entry, sizeof(key_entry));
-+ }
-+
-+ /*
-+ * The cipher types are stored over multiple registers
-+ * starting with SHARED_KEY_MODE_BASE each word will have
-+ * 32 bits and contains the cipher types for 2 bssidx each.
-+ * Using the correct defines correctly will cause overhead,
-+ * so just calculate the correct offset.
-+ */
-+ field.bit_offset = 4 * (key->hw_key_idx % 8);
-+ field.bit_mask = 0x7 << field.bit_offset;
-+
-+ offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);
-+
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+ rt2x00_set_field32(&reg, field,
-+ (crypto->cmd == SET_KEY) * crypto->cipher);
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+
-+ /*
-+ * Update WCID information
-+ */
-+ rt2800_config_wcid(rt2x00dev, crypto->address, key->hw_key_idx);
-+ rt2800_config_wcid_attr_bssidx(rt2x00dev, key->hw_key_idx,
-+ crypto->bssidx);
-+ rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config_shared_key);
-+
-+static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct mac_wcid_entry wcid_entry;
-+ int idx;
-+ u32 offset;
-+
-+ /*
-+ * Search for the first free WCID entry and return the corresponding
-+ * index.
-+ *
-+ * Make sure the WCID starts _after_ the last possible shared key
-+ * entry (>32).
-+ *
-+ * Since parts of the pairwise key table might be shared with
-+ * the beacon frame buffers 6 & 7 we should only write into the
-+ * first 222 entries.
-+ */
-+ for (idx = 33; idx <= 222; idx++) {
-+ offset = MAC_WCID_ENTRY(idx);
-+ rt2800_register_multiread(rt2x00dev, offset, &wcid_entry,
-+ sizeof(wcid_entry));
-+ if (is_broadcast_ether_addr(wcid_entry.mac))
-+ return idx;
-+ }
-+
-+ /*
-+ * Use -1 to indicate that we don't have any more space in the WCID
-+ * table.
-+ */
-+ return -1;
-+}
-+
-+int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_crypto *crypto,
-+ struct ieee80211_key_conf *key)
-+{
-+ struct hw_key_entry key_entry;
-+ u32 offset;
-+
-+ if (crypto->cmd == SET_KEY) {
-+ /*
-+ * Allow key configuration only for STAs that are
-+ * known by the hw.
-+ */
-+ if (crypto->wcid < 0)
-+ return -ENOSPC;
-+ key->hw_key_idx = crypto->wcid;
-+
-+ memcpy(key_entry.key, crypto->key,
-+ sizeof(key_entry.key));
-+ memcpy(key_entry.tx_mic, crypto->tx_mic,
-+ sizeof(key_entry.tx_mic));
-+ memcpy(key_entry.rx_mic, crypto->rx_mic,
-+ sizeof(key_entry.rx_mic));
-+
-+ offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
-+ rt2800_register_multiwrite(rt2x00dev, offset,
-+ &key_entry, sizeof(key_entry));
-+ }
-+
-+ /*
-+ * Update WCID information
-+ */
-+ rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key);
-+
-+int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
-+ struct ieee80211_sta *sta)
-+{
-+ int wcid;
-+ struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
-+
-+ /*
-+ * Find next free WCID.
-+ */
-+ wcid = rt2800_find_wcid(rt2x00dev);
-+
-+ /*
-+ * Store selected wcid even if it is invalid so that we can
-+ * later decide if the STA is uploaded into the hw.
-+ */
-+ sta_priv->wcid = wcid;
-+
-+ /*
-+ * No space left in the device, however, we can still communicate
-+ * with the STA -> No error.
-+ */
-+ if (wcid < 0)
-+ return 0;
-+
-+ /*
-+ * Clean up WCID attributes and write STA address to the device.
-+ */
-+ rt2800_delete_wcid_attr(rt2x00dev, wcid);
-+ rt2800_config_wcid(rt2x00dev, sta->addr, wcid);
-+ rt2800_config_wcid_attr_bssidx(rt2x00dev, wcid,
-+ rt2x00lib_get_bssidx(rt2x00dev, vif));
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_sta_add);
-+
-+int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid)
-+{
-+ /*
-+ * Remove WCID entry, no need to clean the attributes as they will
-+ * get renewed when the WCID is reused.
-+ */
-+ rt2800_config_wcid(rt2x00dev, NULL, wcid);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_sta_remove);
-+
-+void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int filter_flags)
-+{
-+ u32 reg;
-+
-+ /*
-+ * Start configuration steps.
-+ * Note that the version error will always be dropped
-+ * and broadcast frames will always be accepted since
-+ * there is no filter for it at this time.
-+ */
-+ rt2800_register_read(rt2x00dev, RX_FILTER_CFG, &reg);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CRC_ERROR,
-+ !(filter_flags & FIF_FCSFAIL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
-+ !(filter_flags & FIF_PLCPFAIL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
-+ !(filter_flags & FIF_PROMISC_IN_BSS));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
-+ !(filter_flags & FIF_ALLMULTI));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BROADCAST, 0);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_DUPLICATE, 1);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CF_END_ACK,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CF_END,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_ACK,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CTS,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_RTS,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
-+ !(filter_flags & FIF_PSPOLL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 0);
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
-+ !(filter_flags & FIF_CONTROL));
-+ rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config_filter);
-+
-+void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
-+ struct rt2x00intf_conf *conf, const unsigned int flags)
-+{
-+ u32 reg;
-+ bool update_bssid = false;
-+
-+ if (flags & CONFIG_UPDATE_TYPE) {
-+ /*
-+ * Enable synchronisation.
-+ */
-+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+
-+ if (conf->sync == TSF_SYNC_AP_NONE) {
-+ /*
-+ * Tune beacon queue transmit parameters for AP mode
-+ */
-+ rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, &reg);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_CWMIN, 0);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_AIFSN, 1);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_TBTT_ADJUST, 0);
-+ rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
-+ } else {
-+ rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, &reg);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_CWMIN, 4);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_AIFSN, 2);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
-+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_TBTT_ADJUST, 16);
-+ rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
-+ }
-+ }
-+
-+ if (flags & CONFIG_UPDATE_MAC) {
-+ if (flags & CONFIG_UPDATE_TYPE &&
-+ conf->sync == TSF_SYNC_AP_NONE) {
-+ /*
-+ * The BSSID register has to be set to our own mac
-+ * address in AP mode.
-+ */
-+ memcpy(conf->bssid, conf->mac, sizeof(conf->mac));
-+ update_bssid = true;
-+ }
-+
-+ if (!is_zero_ether_addr((const u8 *)conf->mac)) {
-+ reg = le32_to_cpu(conf->mac[1]);
-+ rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
-+ conf->mac[1] = cpu_to_le32(reg);
-+ }
-+
-+ rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0,
-+ conf->mac, sizeof(conf->mac));
-+ }
-+
-+ if ((flags & CONFIG_UPDATE_BSSID) || update_bssid) {
-+ if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
-+ reg = le32_to_cpu(conf->bssid[1]);
-+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
-+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
-+ conf->bssid[1] = cpu_to_le32(reg);
-+ }
-+
-+ rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
-+ conf->bssid, sizeof(conf->bssid));
-+ }
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config_intf);
-+
-+static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_erp *erp)
-+{
-+ bool any_sta_nongf = !!(erp->ht_opmode &
-+ IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-+ u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION;
-+ u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode;
-+ u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate;
-+ u32 reg;
-+
-+ /* default protection rate for HT20: OFDM 24M */
-+ mm20_rate = gf20_rate = 0x4004;
-+
-+ /* default protection rate for HT40: duplicate OFDM 24M */
-+ mm40_rate = gf40_rate = 0x4084;
-+
-+ switch (protection) {
-+ case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
-+ /*
-+ * All STAs in this BSS are HT20/40 but there might be
-+ * STAs not supporting greenfield mode.
-+ * => Disable protection for HT transmissions.
-+ */
-+ mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0;
-+
-+ break;
-+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
-+ /*
-+ * All STAs in this BSS are HT20 or HT20/40 but there
-+ * might be STAs not supporting greenfield mode.
-+ * => Protect all HT40 transmissions.
-+ */
-+ mm20_mode = gf20_mode = 0;
-+ mm40_mode = gf40_mode = 2;
-+
-+ break;
-+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
-+ /*
-+ * Nonmember protection:
-+ * According to 802.11n we _should_ protect all
-+ * HT transmissions (but we don't have to).
-+ *
-+ * But if cts_protection is enabled we _shall_ protect
-+ * all HT transmissions using a CCK rate.
-+ *
-+ * And if any station is non GF we _shall_ protect
-+ * GF transmissions.
-+ *
-+ * We decide to protect everything
-+ * -> fall through to mixed mode.
-+ */
-+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
-+ /*
-+ * Legacy STAs are present
-+ * => Protect all HT transmissions.
-+ */
-+ mm20_mode = mm40_mode = gf20_mode = gf40_mode = 2;
-+
-+ /*
-+ * If erp protection is needed we have to protect HT
-+ * transmissions with CCK 11M long preamble.
-+ */
-+ if (erp->cts_protection) {
-+ /* don't duplicate RTS/CTS in CCK mode */
-+ mm20_rate = mm40_rate = 0x0003;
-+ gf20_rate = gf40_rate = 0x0003;
-+ }
-+ break;
-+ }
-+
-+ /* check for STAs not supporting greenfield mode */
-+ if (any_sta_nongf)
-+ gf20_mode = gf40_mode = 2;
-+
-+ /* Update HT protection config */
-+ rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_RATE, mm20_rate);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode);
-+ rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, mm40_rate);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode);
-+ rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_RATE, gf20_rate);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode);
-+ rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_RATE, gf40_rate);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode);
-+ rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
-+}
-+
-+void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
-+ u32 changed)
-+{
-+ u32 reg;
-+
-+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-+ rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY,
-+ !!erp->short_preamble);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE,
-+ !!erp->short_preamble);
-+ rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
-+ }
-+
-+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
-+ rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL,
-+ erp->cts_protection ? 2 : 0);
-+ rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
-+ }
-+
-+ if (changed & BSS_CHANGED_BASIC_RATES) {
-+ rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE,
-+ erp->basic_rates);
-+ rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
-+ }
-+
-+ if (changed & BSS_CHANGED_ERP_SLOT) {
-+ rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
-+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME,
-+ erp->slot_time);
-+ rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
-+ rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
-+ }
-+
-+ if (changed & BSS_CHANGED_BEACON_INT) {
-+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
-+ erp->beacon_int * 16);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+ }
-+
-+ if (changed & BSS_CHANGED_HT)
-+ rt2800_config_ht_opmode(rt2x00dev, erp);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config_erp);
-+
-+static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+ u16 eeprom;
-+ u8 led_ctrl, led_g_mode, led_r_mode;
-+
-+ rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
-+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
-+ rt2x00_set_field32(&reg, GPIO_SWITCH_0, 1);
-+ rt2x00_set_field32(&reg, GPIO_SWITCH_1, 1);
-+ } else {
-+ rt2x00_set_field32(&reg, GPIO_SWITCH_0, 0);
-+ rt2x00_set_field32(&reg, GPIO_SWITCH_1, 0);
-+ }
-+ rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
-+
-+ rt2800_register_read(rt2x00dev, LED_CFG, &reg);
-+ led_g_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 3 : 0;
-+ led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3;
-+ if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) ||
-+ led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
-+ led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE);
-+ if (led_ctrl == 0 || led_ctrl > 0x40) {
-+ rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, led_g_mode);
-+ rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, led_r_mode);
-+ rt2800_register_write(rt2x00dev, LED_CFG, reg);
-+ } else {
-+ rt2800_mcu_request(rt2x00dev, MCU_BAND_SELECT, 0xff,
-+ (led_g_mode << 2) | led_r_mode, 1);
-+ }
-+ }
-+}
-+
-+static void rt2800_set_ant_diversity(struct rt2x00_dev *rt2x00dev,
-+ enum antenna ant)
-+{
-+ u32 reg;
-+ u8 eesk_pin = (ant == ANTENNA_A) ? 1 : 0;
-+ u8 gpio_bit3 = (ant == ANTENNA_A) ? 0 : 1;
-+
-+ if (rt2x00_is_pci(rt2x00dev)) {
-+ rt2800_register_read(rt2x00dev, E2PROM_CSR, &reg);
-+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK, eesk_pin);
-+ rt2800_register_write(rt2x00dev, E2PROM_CSR, reg);
-+ } else if (rt2x00_is_usb(rt2x00dev))
-+ rt2800_mcu_request(rt2x00dev, MCU_ANT_SELECT, 0xff,
-+ eesk_pin, 0);
-+
-+ rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_DIR3, 0);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL3, gpio_bit3);
-+ rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
-+}
-+
-+void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
-+{
-+ u8 r1;
-+ u8 r3;
-+ u16 eeprom;
-+
-+ rt2800_bbp_read(rt2x00dev, 1, &r1);
-+ rt2800_bbp_read(rt2x00dev, 3, &r3);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3572) &&
-+ test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
-+ rt2800_config_3572bt_ant(rt2x00dev);
-+
-+ /*
-+ * Configure the TX antenna.
-+ */
-+ switch (ant->tx_chain_num) {
-+ case 1:
-+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
-+ break;
-+ case 2:
-+ if (rt2x00_rt(rt2x00dev, RT3572) &&
-+ test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
-+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 1);
-+ else
-+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
-+ break;
-+ case 3:
-+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
-+ break;
-+ }
-+
-+ /*
-+ * Configure the RX antenna.
-+ */
-+ switch (ant->rx_chain_num) {
-+ case 1:
-+ if (rt2x00_rt(rt2x00dev, RT3070) ||
-+ rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
-+ rt2x00_rt(rt2x00dev, RT3390)) {
-+ rt2x00_eeprom_read(rt2x00dev,
-+ EEPROM_NIC_CONF1, &eeprom);
-+ if (rt2x00_get_field16(eeprom,
-+ EEPROM_NIC_CONF1_ANT_DIVERSITY))
-+ rt2800_set_ant_diversity(rt2x00dev,
-+ rt2x00dev->default_ant.rx);
-+ }
-+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
-+ break;
-+ case 2:
-+ if (rt2x00_rt(rt2x00dev, RT3572) &&
-+ test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
-+ rt2x00_set_field8(&r3, BBP3_RX_ADC, 1);
-+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA,
-+ rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
-+ rt2800_set_ant_diversity(rt2x00dev, ANTENNA_B);
-+ } else {
-+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1);
-+ }
-+ break;
-+ case 3:
-+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2);
-+ break;
-+ }
-+
-+ rt2800_bbp_write(rt2x00dev, 3, r3);
-+ rt2800_bbp_write(rt2x00dev, 1, r1);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config_ant);
-+
-+static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_conf *libconf)
-+{
-+ u16 eeprom;
-+ short lna_gain;
-+
-+ if (libconf->rf.channel <= 14) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
-+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG);
-+ } else if (libconf->rf.channel <= 64) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
-+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0);
-+ } else if (libconf->rf.channel <= 128) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
-+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1);
-+ } else {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
-+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2);
-+ }
-+
-+ rt2x00dev->lna_gain = lna_gain;
-+}
-+
-+static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-+
-+ if (rt2x00dev->default_ant.tx_chain_num == 1)
-+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1);
-+
-+ if (rt2x00dev->default_ant.rx_chain_num == 1) {
-+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1);
-+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
-+ } else if (rt2x00dev->default_ant.rx_chain_num == 2)
-+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
-+
-+ if (rf->channel > 14) {
-+ /*
-+ * When TX power is below 0, we should increase it by 7 to
-+ * make it a positive value (Minimum value is -7).
-+ * However this means that values between 0 and 7 have
-+ * double meaning, and we should set a 7DBm boost flag.
-+ */
-+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST,
-+ (info->default_power1 >= 0));
-+
-+ if (info->default_power1 < 0)
-+ info->default_power1 += 7;
-+
-+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1);
-+
-+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST,
-+ (info->default_power2 >= 0));
-+
-+ if (info->default_power2 < 0)
-+ info->default_power2 += 7;
-+
-+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2);
-+ } else {
-+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1);
-+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2);
-+ }
-+
-+ rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
-+
-+ rt2800_rf_write(rt2x00dev, 1, rf->rf1);
-+ rt2800_rf_write(rt2x00dev, 2, rf->rf2);
-+ rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-+ rt2800_rf_write(rt2x00dev, 4, rf->rf4);
-+
-+ udelay(200);
-+
-+ rt2800_rf_write(rt2x00dev, 1, rf->rf1);
-+ rt2800_rf_write(rt2x00dev, 2, rf->rf2);
-+ rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-+ rt2800_rf_write(rt2x00dev, 4, rf->rf4);
-+
-+ udelay(200);
-+
-+ rt2800_rf_write(rt2x00dev, 1, rf->rf1);
-+ rt2800_rf_write(rt2x00dev, 2, rf->rf2);
-+ rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-+ rt2800_rf_write(rt2x00dev, 4, rf->rf4);
-+}
-+
-+static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
-+ u8 rfcsr, calib_tx, calib_rx;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR3_K, rf->rf3);
-+ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2);
-+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1);
-+ rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2);
-+ rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD,
-+ rt2x00dev->default_ant.rx_chain_num <= 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD,
-+ rt2x00dev->default_ant.rx_chain_num <= 2);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD,
-+ rt2x00dev->default_ant.tx_chain_num <= 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD,
-+ rt2x00dev->default_ant.tx_chain_num <= 2);
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-+ msleep(1);
-+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
-+ rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3390)) {
-+ calib_tx = conf_is_ht40(conf) ? 0x68 : 0x4f;
-+ calib_rx = conf_is_ht40(conf) ? 0x6f : 0x4f;
-+ } else {
-+ if (conf_is_ht40(conf)) {
-+ calib_tx = drv_data->calibration_bw40;
-+ calib_rx = drv_data->calibration_bw40;
-+ } else {
-+ calib_tx = drv_data->calibration_bw20;
-+ calib_rx = drv_data->calibration_bw20;
-+ }
-+ }
-+
-+ rt2800_rfcsr_read(rt2x00dev, 24, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR24_TX_CALIB, calib_tx);
-+ rt2800_rfcsr_write(rt2x00dev, 24, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR31_RX_CALIB, calib_rx);
-+ rt2800_rfcsr_write(rt2x00dev, 31, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-+ msleep(1);
-+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-+}
-+
-+static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
-+ u8 rfcsr;
-+ u32 reg;
-+
-+ if (rf->channel <= 14) {
-+ rt2800_bbp_write(rt2x00dev, 25, drv_data->bbp25);
-+ rt2800_bbp_write(rt2x00dev, 26, drv_data->bbp26);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 25, 0x09);
-+ rt2800_bbp_write(rt2x00dev, 26, 0xff);
-+ }
-+
-+ rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1);
-+ rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2);
-+ if (rf->channel <= 14)
-+ rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 2);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 5, &rfcsr);
-+ if (rf->channel <= 14)
-+ rt2x00_set_field8(&rfcsr, RFCSR5_R1, 1);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR5_R1, 2);
-+ rt2800_rfcsr_write(rt2x00dev, 5, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
-+ if (rf->channel <= 14) {
-+ rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 3);
-+ rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
-+ info->default_power1);
-+ } else {
-+ rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 7);
-+ rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
-+ (info->default_power1 & 0x3) |
-+ ((info->default_power1 & 0xC) << 1));
-+ }
-+ rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
-+ if (rf->channel <= 14) {
-+ rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 3);
-+ rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
-+ info->default_power2);
-+ } else {
-+ rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 7);
-+ rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
-+ (info->default_power2 & 0x3) |
-+ ((info->default_power2 & 0xC) << 1));
-+ }
-+ rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
-+ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
-+ if (rf->channel <= 14) {
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
-+ }
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
-+ } else {
-+ switch (rt2x00dev->default_ant.tx_chain_num) {
-+ case 1:
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
-+ case 2:
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
-+ break;
-+ }
-+
-+ switch (rt2x00dev->default_ant.rx_chain_num) {
-+ case 1:
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
-+ case 2:
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
-+ break;
-+ }
-+ }
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
-+ rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
-+
-+ if (conf_is_ht40(conf)) {
-+ rt2800_rfcsr_write(rt2x00dev, 24, drv_data->calibration_bw40);
-+ rt2800_rfcsr_write(rt2x00dev, 31, drv_data->calibration_bw40);
-+ } else {
-+ rt2800_rfcsr_write(rt2x00dev, 24, drv_data->calibration_bw20);
-+ rt2800_rfcsr_write(rt2x00dev, 31, drv_data->calibration_bw20);
-+ }
-+
-+ if (rf->channel <= 14) {
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-+ rfcsr = 0x4c;
-+ rt2x00_set_field8(&rfcsr, RFCSR16_TXMIXER_GAIN,
-+ drv_data->txmixer_gain_24g);
-+ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
-+ rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
-+ } else {
-+ rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_BIT2, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_BIT3, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_BIT4, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_BITS67, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x43);
-+ rfcsr = 0x7a;
-+ rt2x00_set_field8(&rfcsr, RFCSR16_TXMIXER_GAIN,
-+ drv_data->txmixer_gain_5g);
-+ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
-+ rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
-+ if (rf->channel <= 64) {
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0xb7);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xf6);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
-+ } else if (rf->channel <= 128) {
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x74);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xf4);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-+ } else {
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x72);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xf3);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-+ }
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x87);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x9f);
-+ }
-+
-+ rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_DIR7, 0);
-+ if (rf->channel <= 14)
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL7, 1);
-+ else
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL7, 0);
-+ rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
-+}
-+
-+#define POWER_BOUND 0x27
-+#define POWER_BOUND_5G 0x2b
-+#define FREQ_OFFSET_BOUND 0x5f
-+
-+static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
-+ if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
-+ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
-+ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
-+}
-+
-+static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
-+ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
-+ rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2);
-+ rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
-+ if (info->default_power1 > POWER_BOUND)
-+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
-+ rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
-+
-+ rt2800_adjust_freq_offset(rt2x00dev);
-+
-+ if (rf->channel <= 14) {
-+ if (rf->channel == 6)
-+ rt2800_bbp_write(rt2x00dev, 68, 0x0c);
-+ else
-+ rt2800_bbp_write(rt2x00dev, 68, 0x0b);
-+
-+ if (rf->channel >= 1 && rf->channel <= 6)
-+ rt2800_bbp_write(rt2x00dev, 59, 0x0f);
-+ else if (rf->channel >= 7 && rf->channel <= 11)
-+ rt2800_bbp_write(rt2x00dev, 59, 0x0e);
-+ else if (rf->channel >= 12 && rf->channel <= 14)
-+ rt2800_bbp_write(rt2x00dev, 59, 0x0d);
-+ }
-+}
-+
-+static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
-+ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
-+
-+ if (info->default_power1 > POWER_BOUND)
-+ rt2800_rfcsr_write(rt2x00dev, 47, POWER_BOUND);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 47, info->default_power1);
-+
-+ if (info->default_power2 > POWER_BOUND)
-+ rt2800_rfcsr_write(rt2x00dev, 48, POWER_BOUND);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 48, info->default_power2);
-+
-+ rt2800_adjust_freq_offset(rt2x00dev);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
-+
-+ if ( rt2x00dev->default_ant.tx_chain_num == 2 )
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
-+
-+ if ( rt2x00dev->default_ant.rx_chain_num == 2 )
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
-+
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 31, 80);
-+}
-+
-+static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
-+ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
-+ rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2);
-+ rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
-+ if (info->default_power1 > POWER_BOUND)
-+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
-+ rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5392)) {
-+ rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
-+ if (info->default_power1 > POWER_BOUND)
-+ rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR50_TX,
-+ info->default_power2);
-+ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
-+ }
-+
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ if (rt2x00_rt(rt2x00dev, RT5392)) {
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
-+ }
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+
-+ rt2800_adjust_freq_offset(rt2x00dev);
-+
-+ if (rf->channel <= 14) {
-+ int idx = rf->channel-1;
-+
-+ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
-+ /* r55/r59 value array of channel 1~14 */
-+ static const char r55_bt_rev[] = {0x83, 0x83,
-+ 0x83, 0x73, 0x73, 0x63, 0x53, 0x53,
-+ 0x53, 0x43, 0x43, 0x43, 0x43, 0x43};
-+ static const char r59_bt_rev[] = {0x0e, 0x0e,
-+ 0x0e, 0x0e, 0x0e, 0x0b, 0x0a, 0x09,
-+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07};
-+
-+ rt2800_rfcsr_write(rt2x00dev, 55,
-+ r55_bt_rev[idx]);
-+ rt2800_rfcsr_write(rt2x00dev, 59,
-+ r59_bt_rev[idx]);
-+ } else {
-+ static const char r59_bt[] = {0x8b, 0x8b, 0x8b,
-+ 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x89,
-+ 0x88, 0x88, 0x86, 0x85, 0x84};
-+
-+ rt2800_rfcsr_write(rt2x00dev, 59, r59_bt[idx]);
-+ }
-+ } else {
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
-+ static const char r55_nonbt_rev[] = {0x23, 0x23,
-+ 0x23, 0x23, 0x13, 0x13, 0x03, 0x03,
-+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
-+ static const char r59_nonbt_rev[] = {0x07, 0x07,
-+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
-+ 0x07, 0x07, 0x06, 0x05, 0x04, 0x04};
-+
-+ rt2800_rfcsr_write(rt2x00dev, 55,
-+ r55_nonbt_rev[idx]);
-+ rt2800_rfcsr_write(rt2x00dev, 59,
-+ r59_nonbt_rev[idx]);
-+ } else if (rt2x00_rt(rt2x00dev, RT5390) ||
-+ rt2x00_rt(rt2x00dev, RT5392)) {
-+ static const char r59_non_bt[] = {0x8f, 0x8f,
-+ 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d,
-+ 0x8a, 0x88, 0x88, 0x87, 0x87, 0x86};
-+
-+ rt2800_rfcsr_write(rt2x00dev, 59,
-+ r59_non_bt[idx]);
-+ }
-+ }
-+ }
-+}
-+
-+static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ u8 rfcsr, ep_reg;
-+ u32 reg;
-+ int power_bound;
-+
-+ /* TODO */
-+ const bool is_11b = false;
-+ const bool is_type_ep = false;
-+
-+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
-+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL,
-+ (rf->channel > 14 || conf_is_ht40(conf)) ? 5 : 0);
-+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
-+
-+ /* Order of values on rf_channel entry: N, K, mod, R */
-+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1 & 0xff);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 9, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR9_K, rf->rf2 & 0xf);
-+ rt2x00_set_field8(&rfcsr, RFCSR9_N, (rf->rf1 & 0x100) >> 8);
-+ rt2x00_set_field8(&rfcsr, RFCSR9_MOD, ((rf->rf3 - 8) & 0x4) >> 2);
-+ rt2800_rfcsr_write(rt2x00dev, 9, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf4 - 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR11_MOD, (rf->rf3 - 8) & 0x3);
-+ rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
-+
-+ if (rf->channel <= 14) {
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x90);
-+ /* FIXME: RF11 owerwrite ? */
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4A);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x52);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x40);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x4A);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1B);
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0D);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0x9B);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0xD5);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x72);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0E);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0xA2);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0x6B);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0x3E);
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0xA1);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
-+
-+ /* TODO RF27 <- tssi */
-+
-+ rfcsr = rf->channel <= 10 ? 0x07 : 0x06;
-+ rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
-+ rt2800_rfcsr_write(rt2x00dev, 59, rfcsr);
-+
-+ if (is_11b) {
-+ /* CCK */
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0xF8);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0xC0);
-+ if (is_type_ep)
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x06);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x47);
-+ } else {
-+ /* OFDM */
-+ if (is_type_ep)
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x03);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-+ }
-+
-+ power_bound = POWER_BOUND;
-+ ep_reg = 0x2;
-+ } else {
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x97);
-+ /* FIMXE: RF11 overwrite */
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x40);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0xBF);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 37, 0x04);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0xBB);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0xD7);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0x41);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x77);
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x05);
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0x01);
-+
-+ /* TODO RF27 <- tssi */
-+
-+ if (rf->channel >= 36 && rf->channel <= 64) {
-+
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x2E);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x22);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x60);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x7F);
-+ if (rf->channel <= 50)
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x09);
-+ else if (rf->channel >= 52)
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x07);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1C);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x5B);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0X40);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0X00);
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0xFE);
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x0C);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0xF8);
-+ if (rf->channel <= 50) {
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x06),
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0xD3);
-+ } else if (rf->channel >= 52) {
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x04);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0xBB);
-+ }
-+
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x15);
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x7F);
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x15);
-+
-+ } else if (rf->channel >= 100 && rf->channel <= 165) {
-+
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x0E);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x40);
-+ if (rf->channel <= 153) {
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x3C);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x06);
-+ } else if (rf->channel >= 155) {
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x38);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x05);
-+ }
-+ if (rf->channel <= 138) {
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1A);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x3B);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0x20);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0x18);
-+ } else if (rf->channel >= 140) {
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x18);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x1B);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0X08);
-+ }
-+ if (rf->channel <= 124)
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0xFC);
-+ else if (rf->channel >= 126)
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0xEC);
-+ if (rf->channel <= 138)
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x06);
-+ else if (rf->channel >= 140)
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x06);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0xEB);
-+ if (rf->channel <= 138)
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x01);
-+ else if (rf->channel >= 140)
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x00);
-+ if (rf->channel <= 128)
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0xBB);
-+ else if (rf->channel >= 130)
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0xAB);
-+ if (rf->channel <= 116)
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x1D);
-+ else if (rf->channel >= 118)
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x15);
-+ if (rf->channel <= 138)
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x3F);
-+ else if (rf->channel >= 140)
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x7C);
-+ if (rf->channel <= 116)
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x1D);
-+ else if (rf->channel >= 118)
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x15);
-+ }
-+
-+ power_bound = POWER_BOUND_5G;
-+ ep_reg = 0x3;
-+ }
-+
-+ rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
-+ if (info->default_power1 > power_bound)
-+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, power_bound);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
-+ if (is_type_ep)
-+ rt2x00_set_field8(&rfcsr, RFCSR49_EP, ep_reg);
-+ rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
-+ if (info->default_power2 > power_bound)
-+ rt2x00_set_field8(&rfcsr, RFCSR50_TX, power_bound);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR50_TX, info->default_power2);
-+ if (is_type_ep)
-+ rt2x00_set_field8(&rfcsr, RFCSR50_EP, ep_reg);
-+ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
-+
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD,
-+ rt2x00dev->default_ant.tx_chain_num >= 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD,
-+ rt2x00dev->default_ant.tx_chain_num == 2);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
-+
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD,
-+ rt2x00dev->default_ant.rx_chain_num >= 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD,
-+ rt2x00dev->default_ant.rx_chain_num == 2);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0xe4);
-+
-+ if (conf_is_ht40(conf))
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x16);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-+
-+ if (!is_11b) {
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-+ }
-+
-+ /* TODO proper frequency adjustment */
-+ rt2800_adjust_freq_offset(rt2x00dev);
-+
-+ /* TODO merge with others */
-+ rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
-+
-+ /* BBP settings */
-+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
-+
-+ rt2800_bbp_write(rt2x00dev, 79, (rf->channel <= 14) ? 0x1C : 0x18);
-+ rt2800_bbp_write(rt2x00dev, 80, (rf->channel <= 14) ? 0x0E : 0x08);
-+ rt2800_bbp_write(rt2x00dev, 81, (rf->channel <= 14) ? 0x3A : 0x38);
-+ rt2800_bbp_write(rt2x00dev, 82, (rf->channel <= 14) ? 0x62 : 0x92);
-+
-+ /* GLRT band configuration */
-+ rt2800_bbp_write(rt2x00dev, 195, 128);
-+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0xE0 : 0xF0);
-+ rt2800_bbp_write(rt2x00dev, 195, 129);
-+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x1F : 0x1E);
-+ rt2800_bbp_write(rt2x00dev, 195, 130);
-+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x38 : 0x28);
-+ rt2800_bbp_write(rt2x00dev, 195, 131);
-+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x32 : 0x20);
-+ rt2800_bbp_write(rt2x00dev, 195, 133);
-+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x28 : 0x7F);
-+ rt2800_bbp_write(rt2x00dev, 195, 124);
-+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x19 : 0x7F);
-+}
-+
-+static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int word,
-+ const u8 value)
-+{
-+ u8 chain, reg;
-+
-+ for (chain = 0; chain < rt2x00dev->default_ant.rx_chain_num; chain++) {
-+ rt2800_bbp_read(rt2x00dev, 27, &reg);
-+ rt2x00_set_field8(&reg, BBP27_RX_CHAIN_SEL, chain);
-+ rt2800_bbp_write(rt2x00dev, 27, reg);
-+
-+ rt2800_bbp_write(rt2x00dev, word, value);
-+ }
-+}
-+
-+static void rt2800_iq_calibrate(struct rt2x00_dev *rt2x00dev, int channel)
-+{
-+ u8 cal;
-+
-+ /* TX0 IQ Gain */
-+ rt2800_bbp_write(rt2x00dev, 158, 0x2c);
-+ if (channel <= 14)
-+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_GAIN_CAL_TX0_2G);
-+ else if (channel >= 36 && channel <= 64)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5G);
-+ else if (channel >= 100 && channel <= 138)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5G);
-+ else if (channel >= 140 && channel <= 165)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5G);
-+ else
-+ cal = 0;
-+ rt2800_bbp_write(rt2x00dev, 159, cal);
-+
-+ /* TX0 IQ Phase */
-+ rt2800_bbp_write(rt2x00dev, 158, 0x2d);
-+ if (channel <= 14)
-+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_PHASE_CAL_TX0_2G);
-+ else if (channel >= 36 && channel <= 64)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5G);
-+ else if (channel >= 100 && channel <= 138)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5G);
-+ else if (channel >= 140 && channel <= 165)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5G);
-+ else
-+ cal = 0;
-+ rt2800_bbp_write(rt2x00dev, 159, cal);
-+
-+ /* TX1 IQ Gain */
-+ rt2800_bbp_write(rt2x00dev, 158, 0x4a);
-+ if (channel <= 14)
-+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_GAIN_CAL_TX1_2G);
-+ else if (channel >= 36 && channel <= 64)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5G);
-+ else if (channel >= 100 && channel <= 138)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5G);
-+ else if (channel >= 140 && channel <= 165)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5G);
-+ else
-+ cal = 0;
-+ rt2800_bbp_write(rt2x00dev, 159, cal);
-+
-+ /* TX1 IQ Phase */
-+ rt2800_bbp_write(rt2x00dev, 158, 0x4b);
-+ if (channel <= 14)
-+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_PHASE_CAL_TX1_2G);
-+ else if (channel >= 36 && channel <= 64)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5G);
-+ else if (channel >= 100 && channel <= 138)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5G);
-+ else if (channel >= 140 && channel <= 165)
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5G);
-+ else
-+ cal = 0;
-+ rt2800_bbp_write(rt2x00dev, 159, cal);
-+
-+ /* FIXME: possible RX0, RX1 callibration ? */
-+
-+ /* RF IQ compensation control */
-+ rt2800_bbp_write(rt2x00dev, 158, 0x04);
-+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_RF_IQ_COMPENSATION_CONTROL);
-+ rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0);
-+
-+ /* RF IQ imbalance compensation control */
-+ rt2800_bbp_write(rt2x00dev, 158, 0x03);
-+ cal = rt2x00_eeprom_byte(rt2x00dev,
-+ EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CONTROL);
-+ rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0);
-+}
-+
-+static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_conf *conf,
-+ struct rf_channel *rf,
-+ struct channel_info *info)
-+{
-+ u32 reg;
-+ unsigned int tx_pin;
-+ u8 bbp, rfcsr;
-+
-+ if (rf->channel <= 14) {
-+ info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
-+ info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2);
-+ } else {
-+ info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1);
-+ info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2);
-+ }
-+
-+ switch (rt2x00dev->chip.rf) {
-+ case RF2020:
-+ case RF3020:
-+ case RF3021:
-+ case RF3022:
-+ case RF3320:
-+ rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
-+ break;
-+ case RF3052:
-+ rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
-+ break;
-+ case RF3290:
-+ rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info);
-+ break;
-+ case RF3322:
-+ rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info);
-+ break;
-+ case RF5360:
-+ case RF5370:
-+ case RF5372:
-+ case RF5390:
-+ case RF5392:
-+ rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
-+ break;
-+ case RF5592:
-+ rt2800_config_channel_rf55xx(rt2x00dev, conf, rf, info);
-+ break;
-+ default:
-+ rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
-+ }
-+
-+ if (rt2x00_rf(rt2x00dev, RF3290) ||
-+ rt2x00_rf(rt2x00dev, RF3322) ||
-+ rt2x00_rf(rt2x00dev, RF5360) ||
-+ rt2x00_rf(rt2x00dev, RF5370) ||
-+ rt2x00_rf(rt2x00dev, RF5372) ||
-+ rt2x00_rf(rt2x00dev, RF5390) ||
-+ rt2x00_rf(rt2x00dev, RF5392)) {
-+ rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
-+ }
-+
-+ /*
-+ * Change BBP settings
-+ */
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_write(rt2x00dev, 27, 0x0);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 27, 0x20);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
-+ rt2800_bbp_write(rt2x00dev, 86, 0);
-+ }
-+
-+ if (rf->channel <= 14) {
-+ if (!rt2x00_rt(rt2x00dev, RT5390) &&
-+ !rt2x00_rt(rt2x00dev, RT5392)) {
-+ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG,
-+ &rt2x00dev->cap_flags)) {
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+ rt2800_bbp_write(rt2x00dev, 75, 0x46);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 82, 0x84);
-+ rt2800_bbp_write(rt2x00dev, 75, 0x50);
-+ }
-+ }
-+ } else {
-+ if (rt2x00_rt(rt2x00dev, RT3572))
-+ rt2800_bbp_write(rt2x00dev, 82, 0x94);
-+ else
-+ rt2800_bbp_write(rt2x00dev, 82, 0xf2);
-+
-+ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
-+ rt2800_bbp_write(rt2x00dev, 75, 0x46);
-+ else
-+ rt2800_bbp_write(rt2x00dev, 75, 0x50);
-+ }
-+
-+ rt2800_register_read(rt2x00dev, TX_BAND_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_MINUS, conf_is_ht40_minus(conf));
-+ rt2x00_set_field32(&reg, TX_BAND_CFG_A, rf->channel > 14);
-+ rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
-+ rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3572))
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0);
-+
-+ tx_pin = 0;
-+
-+ switch (rt2x00dev->default_ant.tx_chain_num) {
-+ case 3:
-+ /* Turn on tertiary PAs */
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A2_EN,
-+ rf->channel > 14);
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G2_EN,
-+ rf->channel <= 14);
-+ /* fall-through */
-+ case 2:
-+ /* Turn on secondary PAs */
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN,
-+ rf->channel > 14);
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN,
-+ rf->channel <= 14);
-+ /* fall-through */
-+ case 1:
-+ /* Turn on primary PAs */
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN,
-+ rf->channel > 14);
-+ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
-+ else
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN,
-+ rf->channel <= 14);
-+ break;
-+ }
-+
-+ switch (rt2x00dev->default_ant.rx_chain_num) {
-+ case 3:
-+ /* Turn on tertiary LNAs */
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN, 1);
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN, 1);
-+ /* fall-through */
-+ case 2:
-+ /* Turn on secondary LNAs */
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
-+ /* fall-through */
-+ case 1:
-+ /* Turn on primary LNAs */
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
-+ break;
-+ }
-+
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
-+
-+ rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3572))
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0x80);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5592)) {
-+ rt2800_bbp_write(rt2x00dev, 195, 141);
-+ rt2800_bbp_write(rt2x00dev, 196, conf_is_ht40(conf) ? 0x10 : 0x1a);
-+
-+ /* AGC init */
-+ reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2 * rt2x00dev->lna_gain;
-+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
-+
-+ rt2800_iq_calibrate(rt2x00dev, rf->channel);
-+ }
-+
-+ rt2800_bbp_read(rt2x00dev, 4, &bbp);
-+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
-+ rt2800_bbp_write(rt2x00dev, 4, bbp);
-+
-+ rt2800_bbp_read(rt2x00dev, 3, &bbp);
-+ rt2x00_set_field8(&bbp, BBP3_HT40_MINUS, conf_is_ht40_minus(conf));
-+ rt2800_bbp_write(rt2x00dev, 3, bbp);
-+
-+ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
-+ if (conf_is_ht40(conf)) {
-+ rt2800_bbp_write(rt2x00dev, 69, 0x1a);
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x16);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 69, 0x16);
-+ rt2800_bbp_write(rt2x00dev, 70, 0x08);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x11);
-+ }
-+ }
-+
-+ msleep(1);
-+
-+ /*
-+ * Clear channel statistic counters
-+ */
-+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &reg);
-+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &reg);
-+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
-+
-+ /*
-+ * Clear update flag
-+ */
-+ if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_bbp_read(rt2x00dev, 49, &bbp);
-+ rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0);
-+ rt2800_bbp_write(rt2x00dev, 49, bbp);
-+ }
-+}
-+
-+static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 tssi_bounds[9];
-+ u8 current_tssi;
-+ u16 eeprom;
-+ u8 step;
-+ int i;
-+
-+ /*
-+ * First check if temperature compensation is supported.
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+ if (!rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC))
-+ return 0;
-+
-+ /*
-+ * Read TSSI boundaries for temperature compensation from
-+ * the EEPROM.
-+ *
-+ * Array idx 0 1 2 3 4 5 6 7 8
-+ * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4
-+ * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00
-+ */
-+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom);
-+ tssi_bounds[0] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG1_MINUS4);
-+ tssi_bounds[1] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG1_MINUS3);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom);
-+ tssi_bounds[2] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG2_MINUS2);
-+ tssi_bounds[3] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG2_MINUS1);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom);
-+ tssi_bounds[4] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG3_REF);
-+ tssi_bounds[5] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG3_PLUS1);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom);
-+ tssi_bounds[6] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG4_PLUS2);
-+ tssi_bounds[7] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG4_PLUS3);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom);
-+ tssi_bounds[8] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG5_PLUS4);
-+
-+ step = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_BG5_AGC_STEP);
-+ } else {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom);
-+ tssi_bounds[0] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A1_MINUS4);
-+ tssi_bounds[1] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A1_MINUS3);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom);
-+ tssi_bounds[2] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A2_MINUS2);
-+ tssi_bounds[3] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A2_MINUS1);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom);
-+ tssi_bounds[4] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A3_REF);
-+ tssi_bounds[5] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A3_PLUS1);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom);
-+ tssi_bounds[6] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A4_PLUS2);
-+ tssi_bounds[7] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A4_PLUS3);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom);
-+ tssi_bounds[8] = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A5_PLUS4);
-+
-+ step = rt2x00_get_field16(eeprom,
-+ EEPROM_TSSI_BOUND_A5_AGC_STEP);
-+ }
-+
-+ /*
-+ * Check if temperature compensation is supported.
-+ */
-+ if (tssi_bounds[4] == 0xff || step == 0xff)
-+ return 0;
-+
-+ /*
-+ * Read current TSSI (BBP 49).
-+ */
-+ rt2800_bbp_read(rt2x00dev, 49, &current_tssi);
-+
-+ /*
-+ * Compare TSSI value (BBP49) with the compensation boundaries
-+ * from the EEPROM and increase or decrease tx power.
-+ */
-+ for (i = 0; i <= 3; i++) {
-+ if (current_tssi > tssi_bounds[i])
-+ break;
-+ }
-+
-+ if (i == 4) {
-+ for (i = 8; i >= 5; i--) {
-+ if (current_tssi < tssi_bounds[i])
-+ break;
-+ }
-+ }
-+
-+ return (i - 4) * step;
-+}
-+
-+static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
-+ enum ieee80211_band band)
-+{
-+ u16 eeprom;
-+ u8 comp_en;
-+ u8 comp_type;
-+ int comp_value = 0;
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom);
-+
-+ /*
-+ * HT40 compensation not required.
-+ */
-+ if (eeprom == 0xffff ||
-+ !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
-+ return 0;
-+
-+ if (band == IEEE80211_BAND_2GHZ) {
-+ comp_en = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_DELTA_ENABLE_2G);
-+ if (comp_en) {
-+ comp_type = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_DELTA_TYPE_2G);
-+ comp_value = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_DELTA_VALUE_2G);
-+ if (!comp_type)
-+ comp_value = -comp_value;
-+ }
-+ } else {
-+ comp_en = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_DELTA_ENABLE_5G);
-+ if (comp_en) {
-+ comp_type = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_DELTA_TYPE_5G);
-+ comp_value = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_DELTA_VALUE_5G);
-+ if (!comp_type)
-+ comp_value = -comp_value;
-+ }
-+ }
-+
-+ return comp_value;
-+}
-+
-+static int rt2800_get_txpower_reg_delta(struct rt2x00_dev *rt2x00dev,
-+ int power_level, int max_power)
-+{
-+ int delta;
-+
-+ if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags))
-+ return 0;
-+
-+ /*
-+ * XXX: We don't know the maximum transmit power of our hardware since
-+ * the EEPROM doesn't expose it. We only know that we are calibrated
-+ * to 100% tx power.
-+ *
-+ * Hence, we assume the regulatory limit that cfg80211 calulated for
-+ * the current channel is our maximum and if we are requested to lower
-+ * the value we just reduce our tx power accordingly.
-+ */
-+ delta = power_level - max_power;
-+ return min(delta, 0);
-+}
-+
-+static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
-+ enum ieee80211_band band, int power_level,
-+ u8 txpower, int delta)
-+{
-+ u16 eeprom;
-+ u8 criterion;
-+ u8 eirp_txpower;
-+ u8 eirp_txpower_criterion;
-+ u8 reg_limit;
-+
-+ if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
-+ /*
-+ * Check if eirp txpower exceed txpower_limit.
-+ * We use OFDM 6M as criterion and its eirp txpower
-+ * is stored at EEPROM_EIRP_MAX_TX_POWER.
-+ * .11b data rate need add additional 4dbm
-+ * when calculating eirp txpower.
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + 1,
-+ &eeprom);
-+ criterion = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE0);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER,
-+ &eeprom);
-+
-+ if (band == IEEE80211_BAND_2GHZ)
-+ eirp_txpower_criterion = rt2x00_get_field16(eeprom,
-+ EEPROM_EIRP_MAX_TX_POWER_2GHZ);
-+ else
-+ eirp_txpower_criterion = rt2x00_get_field16(eeprom,
-+ EEPROM_EIRP_MAX_TX_POWER_5GHZ);
-+
-+ eirp_txpower = eirp_txpower_criterion + (txpower - criterion) +
-+ (is_rate_b ? 4 : 0) + delta;
-+
-+ reg_limit = (eirp_txpower > power_level) ?
-+ (eirp_txpower - power_level) : 0;
-+ } else
-+ reg_limit = 0;
-+
-+ txpower = max(0, txpower + delta - reg_limit);
-+ return min_t(u8, txpower, 0xc);
-+}
-+
-+/*
-+ * We configure transmit power using MAC TX_PWR_CFG_{0,...,N} registers and
-+ * BBP R1 register. TX_PWR_CFG_X allow to configure per rate TX power values,
-+ * 4 bits for each rate (tune from 0 to 15 dBm). BBP_R1 controls transmit power
-+ * for all rates, but allow to set only 4 discrete values: -12, -6, 0 and 6 dBm.
-+ * Reference per rate transmit power values are located in the EEPROM at
-+ * EEPROM_TXPOWER_BYRATE offset. We adjust them and BBP R1 settings according to
-+ * current conditions (i.e. band, bandwidth, temperature, user settings).
-+ */
-+static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
-+ struct ieee80211_channel *chan,
-+ int power_level)
-+{
-+ u8 txpower, r1;
-+ u16 eeprom;
-+ u32 reg, offset;
-+ int i, is_rate_b, delta, power_ctrl;
-+ enum ieee80211_band band = chan->band;
-+
-+ /*
-+ * Calculate HT40 compensation. For 40MHz we need to add or subtract
-+ * value read from EEPROM (different for 2GHz and for 5GHz).
-+ */
-+ delta = rt2800_get_txpower_bw_comp(rt2x00dev, band);
-+
-+ /*
-+ * Calculate temperature compensation. Depends on measurement of current
-+ * TSSI (Transmitter Signal Strength Indication) we know TX power (due
-+ * to temperature or maybe other factors) is smaller or bigger than
-+ * expected. We adjust it, based on TSSI reference and boundaries values
-+ * provided in EEPROM.
-+ */
-+ delta += rt2800_get_gain_calibration_delta(rt2x00dev);
-+
-+ /*
-+ * Decrease power according to user settings, on devices with unknown
-+ * maximum tx power. For other devices we take user power_level into
-+ * consideration on rt2800_compensate_txpower().
-+ */
-+ delta += rt2800_get_txpower_reg_delta(rt2x00dev, power_level,
-+ chan->max_power);
-+
-+ /*
-+ * BBP_R1 controls TX power for all rates, it allow to set the following
-+ * gains -12, -6, 0, +6 dBm by setting values 2, 1, 0, 3 respectively.
-+ *
-+ * TODO: we do not use +6 dBm option to do not increase power beyond
-+ * regulatory limit, however this could be utilized for devices with
-+ * CAPABILITY_POWER_LIMIT.
-+ *
-+ * TODO: add different temperature compensation code for RT3290 & RT5390
-+ * to allow to use BBP_R1 for those chips.
-+ */
-+ if (!rt2x00_rt(rt2x00dev, RT3290) &&
-+ !rt2x00_rt(rt2x00dev, RT5390)) {
-+ rt2800_bbp_read(rt2x00dev, 1, &r1);
-+ if (delta <= -12) {
-+ power_ctrl = 2;
-+ delta += 12;
-+ } else if (delta <= -6) {
-+ power_ctrl = 1;
-+ delta += 6;
-+ } else {
-+ power_ctrl = 0;
-+ }
-+ rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl);
-+ rt2800_bbp_write(rt2x00dev, 1, r1);
-+ }
-+
-+ offset = TX_PWR_CFG_0;
-+
-+ for (i = 0; i < EEPROM_TXPOWER_BYRATE_SIZE; i += 2) {
-+ /* just to be safe */
-+ if (offset > TX_PWR_CFG_4)
-+ break;
-+
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+
-+ /* read the next four txpower values */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i,
-+ &eeprom);
-+
-+ is_rate_b = i ? 0 : 1;
-+ /*
-+ * TX_PWR_CFG_0: 1MBS, TX_PWR_CFG_1: 24MBS,
-+ * TX_PWR_CFG_2: MCS4, TX_PWR_CFG_3: MCS12,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE0);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE0, txpower);
-+
-+ /*
-+ * TX_PWR_CFG_0: 2MBS, TX_PWR_CFG_1: 36MBS,
-+ * TX_PWR_CFG_2: MCS5, TX_PWR_CFG_3: MCS13,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE1);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE1, txpower);
-+
-+ /*
-+ * TX_PWR_CFG_0: 5.5MBS, TX_PWR_CFG_1: 48MBS,
-+ * TX_PWR_CFG_2: MCS6, TX_PWR_CFG_3: MCS14,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE2);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE2, txpower);
-+
-+ /*
-+ * TX_PWR_CFG_0: 11MBS, TX_PWR_CFG_1: 54MBS,
-+ * TX_PWR_CFG_2: MCS7, TX_PWR_CFG_3: MCS15,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE3);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3, txpower);
-+
-+ /* read the next four txpower values */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1,
-+ &eeprom);
-+
-+ is_rate_b = 0;
-+ /*
-+ * TX_PWR_CFG_0: 6MBS, TX_PWR_CFG_1: MCS0,
-+ * TX_PWR_CFG_2: MCS8, TX_PWR_CFG_3: unknown,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE0);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE4, txpower);
-+
-+ /*
-+ * TX_PWR_CFG_0: 9MBS, TX_PWR_CFG_1: MCS1,
-+ * TX_PWR_CFG_2: MCS9, TX_PWR_CFG_3: unknown,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE1);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE5, txpower);
-+
-+ /*
-+ * TX_PWR_CFG_0: 12MBS, TX_PWR_CFG_1: MCS2,
-+ * TX_PWR_CFG_2: MCS10, TX_PWR_CFG_3: unknown,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE2);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE6, txpower);
-+
-+ /*
-+ * TX_PWR_CFG_0: 18MBS, TX_PWR_CFG_1: MCS3,
-+ * TX_PWR_CFG_2: MCS11, TX_PWR_CFG_3: unknown,
-+ * TX_PWR_CFG_4: unknown
-+ */
-+ txpower = rt2x00_get_field16(eeprom,
-+ EEPROM_TXPOWER_BYRATE_RATE3);
-+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
-+ power_level, txpower, delta);
-+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE7, txpower);
-+
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+
-+ /* next TX_PWR_CFG register */
-+ offset += 4;
-+ }
-+}
-+
-+void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.chandef.chan,
-+ rt2x00dev->tx_power);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
-+
-+void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 tx_pin;
-+ u8 rfcsr;
-+
-+ /*
-+ * A voltage-controlled oscillator(VCO) is an electronic oscillator
-+ * designed to be controlled in oscillation frequency by a voltage
-+ * input. Maybe the temperature will affect the frequency of
-+ * oscillation to be shifted. The VCO calibration will be called
-+ * periodically to adjust the frequency to be precision.
-+ */
-+
-+ rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin);
-+ tx_pin &= TX_PIN_CFG_PA_PE_DISABLE;
-+ rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
-+
-+ switch (rt2x00dev->chip.rf) {
-+ case RF2020:
-+ case RF3020:
-+ case RF3021:
-+ case RF3022:
-+ case RF3320:
-+ case RF3052:
-+ rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
-+ break;
-+ case RF3290:
-+ case RF5360:
-+ case RF5370:
-+ case RF5372:
-+ case RF5390:
-+ case RF5392:
-+ rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
-+ break;
-+ default:
-+ return;
-+ }
-+
-+ mdelay(1);
-+
-+ rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin);
-+ if (rt2x00dev->rf_channel <= 14) {
-+ switch (rt2x00dev->default_ant.tx_chain_num) {
-+ case 3:
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G2_EN, 1);
-+ /* fall through */
-+ case 2:
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
-+ /* fall through */
-+ case 1:
-+ default:
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
-+ break;
-+ }
-+ } else {
-+ switch (rt2x00dev->default_ant.tx_chain_num) {
-+ case 3:
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A2_EN, 1);
-+ /* fall through */
-+ case 2:
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
-+ /* fall through */
-+ case 1:
-+ default:
-+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, 1);
-+ break;
-+ }
-+ }
-+ rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
-+
-+}
-+EXPORT_SYMBOL_GPL(rt2800_vco_calibration);
-+
-+static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_conf *libconf)
-+{
-+ u32 reg;
-+
-+ rt2800_register_read(rt2x00dev, TX_RTY_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_SHORT_RTY_LIMIT,
-+ libconf->conf->short_frame_max_tx_count);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT,
-+ libconf->conf->long_frame_max_tx_count);
-+ rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg);
-+}
-+
-+static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_conf *libconf)
-+{
-+ enum dev_state state =
-+ (libconf->conf->flags & IEEE80211_CONF_PS) ?
-+ STATE_SLEEP : STATE_AWAKE;
-+ u32 reg;
-+
-+ if (state == STATE_SLEEP) {
-+ rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0);
-+
-+ rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
-+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5);
-+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE,
-+ libconf->conf->listen_interval - 1);
-+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 1);
-+ rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
-+
-+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
-+ } else {
-+ rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
-+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0);
-+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0);
-+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 0);
-+ rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
-+
-+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
-+ }
-+}
-+
-+void rt2800_config(struct rt2x00_dev *rt2x00dev,
-+ struct rt2x00lib_conf *libconf,
-+ const unsigned int flags)
-+{
-+ /* Always recalculate LNA gain before changing configuration */
-+ rt2800_config_lna_gain(rt2x00dev, libconf);
-+
-+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
-+ rt2800_config_channel(rt2x00dev, libconf->conf,
-+ &libconf->rf, &libconf->channel);
-+ rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan,
-+ libconf->conf->power_level);
-+ }
-+ if (flags & IEEE80211_CONF_CHANGE_POWER)
-+ rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan,
-+ libconf->conf->power_level);
-+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
-+ rt2800_config_retry_limit(rt2x00dev, libconf);
-+ if (flags & IEEE80211_CONF_CHANGE_PS)
-+ rt2800_config_ps(rt2x00dev, libconf);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_config);
-+
-+/*
-+ * Link tuning
-+ */
-+void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual)
-+{
-+ u32 reg;
-+
-+ /*
-+ * Update FCS error count from register.
-+ */
-+ rt2800_register_read(rt2x00dev, RX_STA_CNT0, &reg);
-+ qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_link_stats);
-+
-+static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 vgc;
-+
-+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-+ if (rt2x00_rt(rt2x00dev, RT3070) ||
-+ rt2x00_rt(rt2x00dev, RT3071) ||
-+ rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3390) ||
-+ rt2x00_rt(rt2x00dev, RT3572) ||
-+ rt2x00_rt(rt2x00dev, RT5390) ||
-+ rt2x00_rt(rt2x00dev, RT5392) ||
-+ rt2x00_rt(rt2x00dev, RT5592))
-+ vgc = 0x1c + (2 * rt2x00dev->lna_gain);
-+ else
-+ vgc = 0x2e + rt2x00dev->lna_gain;
-+ } else { /* 5GHZ band */
-+ if (rt2x00_rt(rt2x00dev, RT3572))
-+ vgc = 0x22 + (rt2x00dev->lna_gain * 5) / 3;
-+ else if (rt2x00_rt(rt2x00dev, RT5592))
-+ vgc = 0x24 + (2 * rt2x00dev->lna_gain);
-+ else {
-+ if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
-+ vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3;
-+ else
-+ vgc = 0x3a + (rt2x00dev->lna_gain * 5) / 3;
-+ }
-+ }
-+
-+ return vgc;
-+}
-+
-+static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev,
-+ struct link_qual *qual, u8 vgc_level)
-+{
-+ if (qual->vgc_level != vgc_level) {
-+ if (rt2x00_rt(rt2x00dev, RT5592)) {
-+ rt2800_bbp_write(rt2x00dev, 83, qual->rssi > -65 ? 0x4a : 0x7a);
-+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, vgc_level);
-+ } else
-+ rt2800_bbp_write(rt2x00dev, 66, vgc_level);
-+ qual->vgc_level = vgc_level;
-+ qual->vgc_level_reg = vgc_level;
-+ }
-+}
-+
-+void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual)
-+{
-+ rt2800_set_vgc(rt2x00dev, qual, rt2800_get_default_vgc(rt2x00dev));
-+}
-+EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
-+
-+void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
-+ const u32 count)
-+{
-+ u8 vgc;
-+
-+ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C))
-+ return;
-+ /*
-+ * When RSSI is better then -80 increase VGC level with 0x10, except
-+ * for rt5592 chip.
-+ */
-+
-+ vgc = rt2800_get_default_vgc(rt2x00dev);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5592)) {
-+ if (qual->rssi > -65)
-+ vgc += 0x20;
-+ } else {
-+ if (qual->rssi > -80)
-+ vgc += 0x10;
-+ }
-+
-+ rt2800_set_vgc(rt2x00dev, qual, vgc);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_link_tuner);
-+
-+/*
-+ * Initialization functions.
-+ */
-+static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+ u16 eeprom;
-+ unsigned int i;
-+ int ret;
-+
-+ rt2800_disable_wpdma(rt2x00dev);
-+
-+ ret = rt2800_drv_init_registers(rt2x00dev);
-+ if (ret)
-+ return ret;
-+
-+ rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
-+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
-+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */
-+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */
-+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */
-+ rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg);
-+
-+ rt2800_register_read(rt2x00dev, BCN_OFFSET1, &reg);
-+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */
-+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */
-+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */
-+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */
-+ rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg);
-+
-+ rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
-+ rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
-+
-+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
-+
-+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 1600);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, 0);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
-+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-+
-+ rt2800_config_filter(rt2x00dev, FIF_ALLMULTI);
-+
-+ rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
-+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, 9);
-+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
-+ rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290)) {
-+ rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-+ if (rt2x00_get_field32(reg, WLAN_EN) == 1) {
-+ rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 1);
-+ rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-+ }
-+
-+ rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
-+ if (!(rt2x00_get_field32(reg, LDO0_EN) == 1)) {
-+ rt2x00_set_field32(&reg, LDO0_EN, 1);
-+ rt2x00_set_field32(&reg, LDO_BGSEL, 3);
-+ rt2800_register_write(rt2x00dev, CMB_CTRL, reg);
-+ }
-+
-+ rt2800_register_read(rt2x00dev, OSC_CTRL, &reg);
-+ rt2x00_set_field32(&reg, OSC_ROSC_EN, 1);
-+ rt2x00_set_field32(&reg, OSC_CAL_REQ, 1);
-+ rt2x00_set_field32(&reg, OSC_REF_CYCLE, 0x27);
-+ rt2800_register_write(rt2x00dev, OSC_CTRL, reg);
-+
-+ rt2800_register_read(rt2x00dev, COEX_CFG0, &reg);
-+ rt2x00_set_field32(&reg, COEX_CFG_ANT, 0x5e);
-+ rt2800_register_write(rt2x00dev, COEX_CFG0, reg);
-+
-+ rt2800_register_read(rt2x00dev, COEX_CFG2, &reg);
-+ rt2x00_set_field32(&reg, BT_COEX_CFG1, 0x00);
-+ rt2x00_set_field32(&reg, BT_COEX_CFG0, 0x17);
-+ rt2x00_set_field32(&reg, WL_COEX_CFG1, 0x93);
-+ rt2x00_set_field32(&reg, WL_COEX_CFG0, 0x7f);
-+ rt2800_register_write(rt2x00dev, COEX_CFG2, reg);
-+
-+ rt2800_register_read(rt2x00dev, PLL_CTRL, &reg);
-+ rt2x00_set_field32(&reg, PLL_CONTROL, 1);
-+ rt2800_register_write(rt2x00dev, PLL_CTRL, reg);
-+ }
-+
-+ if (rt2x00_rt(rt2x00dev, RT3071) ||
-+ rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT3390)) {
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290))
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0,
-+ 0x00000404);
-+ else
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0,
-+ 0x00000400);
-+
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2,
-+ 0x0000002c);
-+ else
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2,
-+ 0x0000000f);
-+ } else {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
-+ }
-+ } else if (rt2x00_rt(rt2x00dev, RT3070)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
-+
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000002c);
-+ } else {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
-+ }
-+ } else if (rt2800_is_305x_soc(rt2x00dev)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030);
-+ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
-+ } else if (rt2x00_rt(rt2x00dev, RT3572)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-+ } else if (rt2x00_rt(rt2x00dev, RT5390) ||
-+ rt2x00_rt(rt2x00dev, RT5392) ||
-+ rt2x00_rt(rt2x00dev, RT5592)) {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
-+ } else {
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
-+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-+ }
-+
-+ rt2800_register_read(rt2x00dev, TX_LINK_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_MFB_ENABLE, 0);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_MRQ_EN, 0);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_RDG_EN, 0);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_CF_ACK_EN, 1);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFB, 0);
-+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFS, 0);
-+ rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9);
-+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 32);
-+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10);
-+ rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
-+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT2872, REV_RT2872E) ||
-+ rt2x00_rt(rt2x00dev, RT2883) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070E))
-+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
-+ else
-+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
-+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_PSDU, 0);
-+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_MPDU, 0);
-+ rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, LED_CFG, &reg);
-+ rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, 70);
-+ rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, 30);
-+ rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
-+ rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
-+ rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 3);
-+ rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
-+ rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
-+ rt2800_register_write(rt2x00dev, LED_CFG, reg);
-+
-+ rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f);
-+
-+ rt2800_register_read(rt2x00dev, TX_RTY_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_SHORT_RTY_LIMIT, 15);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT, 31);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
-+ rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
-+ rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AUTORESPONDER, 1);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY, 1);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MMODE, 0);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MREF, 0);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE, 1);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_DUAL_CTS_EN, 0);
-+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0);
-+ rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 3);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_CTRL, 0);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_NAV_SHORT, 1);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
-+ rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 3);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL, 0);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_NAV_SHORT, 1);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
-+ rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_RATE, 0x4004);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_CTRL, 0);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_NAV_SHORT, 1);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, 0);
-+ rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, 0x4084);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, 0);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_NAV_SHORT, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, 0);
-+ rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_RATE, 0x4004);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_CTRL, 0);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_NAV_SHORT, 1);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, 0);
-+ rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_RATE, 0x4084);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_CTRL, 0);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_NAV_SHORT, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, 0);
-+ rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
-+
-+ if (rt2x00_is_usb(rt2x00dev)) {
-+ rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
-+
-+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_BIG_ENDIAN, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_HDR_SEG_LEN, 0);
-+ rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-+ }
-+
-+ /*
-+ * The legacy driver also sets TXOP_CTRL_CFG_RESERVED_TRUN_EN to 1
-+ * although it is reserved.
-+ */
-+ rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG, &reg);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_TIMEOUT_TRUN_EN, 1);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_AC_TRUN_EN, 1);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN, 1);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_USER_MODE_TRUN_EN, 1);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_MIMO_PS_TRUN_EN, 1);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_RESERVED_TRUN_EN, 1);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_LSIG_TXOP_EN, 0);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CCA_EN, 0);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CCA_DLY, 88);
-+ rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CWMIN, 0);
-+ rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, reg);
-+
-+ reg = rt2x00_rt(rt2x00dev, RT5592) ? 0x00000082 : 0x00000002;
-+ rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, reg);
-+
-+ rt2800_register_read(rt2x00dev, TX_RTS_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32);
-+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES,
-+ IEEE80211_MAX_RTS_THRESHOLD);
-+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_FBK_EN, 0);
-+ rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg);
-+
-+ rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
-+
-+ /*
-+ * Usually the CCK SIFS time should be set to 10 and the OFDM SIFS
-+ * time should be set to 16. However, the original Ralink driver uses
-+ * 16 for both and indeed using a value of 10 for CCK SIFS results in
-+ * connection problems with 11g + CTS protection. Hence, use the same
-+ * defaults as the Ralink driver: 16 for both, CCK and OFDM SIFS.
-+ */
-+ rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 16);
-+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 16);
-+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
-+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, 314);
-+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
-+ rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
-+
-+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
-+
-+ /*
-+ * ASIC will keep garbage value after boot, clear encryption keys.
-+ */
-+ for (i = 0; i < 4; i++)
-+ rt2800_register_write(rt2x00dev,
-+ SHARED_KEY_MODE_ENTRY(i), 0);
-+
-+ for (i = 0; i < 256; i++) {
-+ rt2800_config_wcid(rt2x00dev, NULL, i);
-+ rt2800_delete_wcid_attr(rt2x00dev, i);
-+ rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
-+ }
-+
-+ /*
-+ * Clear all beacons
-+ */
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE0);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE1);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE2);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE3);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE4);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE5);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE6);
-+ rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE7);
-+
-+ if (rt2x00_is_usb(rt2x00dev)) {
-+ rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
-+ rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 30);
-+ rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
-+ } else if (rt2x00_is_pcie(rt2x00dev)) {
-+ rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
-+ rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 125);
-+ rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
-+ }
-+
-+ rt2800_register_read(rt2x00dev, HT_FBK_CFG0, &reg);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS0FBK, 0);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS1FBK, 0);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS2FBK, 1);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS3FBK, 2);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS4FBK, 3);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS5FBK, 4);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS6FBK, 5);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS7FBK, 6);
-+ rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg);
-+
-+ rt2800_register_read(rt2x00dev, HT_FBK_CFG1, &reg);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS8FBK, 8);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS9FBK, 8);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS10FBK, 9);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS11FBK, 10);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS12FBK, 11);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS13FBK, 12);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS14FBK, 13);
-+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS15FBK, 14);
-+ rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg);
-+
-+ rt2800_register_read(rt2x00dev, LG_FBK_CFG0, &reg);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS0FBK, 8);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS1FBK, 8);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 9);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 10);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 11);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 12);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS6FBK, 13);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS7FBK, 14);
-+ rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg);
-+
-+ rt2800_register_read(rt2x00dev, LG_FBK_CFG1, &reg);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS0FBK, 0);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS1FBK, 0);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS2FBK, 1);
-+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS3FBK, 2);
-+ rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg);
-+
-+ /*
-+ * Do not force the BA window size, we use the TXWI to set it
-+ */
-+ rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE, &reg);
-+ rt2x00_set_field32(&reg, AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE, 0);
-+ rt2x00_set_field32(&reg, AMPDU_BA_WINSIZE_FORCE_WINSIZE, 0);
-+ rt2800_register_write(rt2x00dev, AMPDU_BA_WINSIZE, reg);
-+
-+ /*
-+ * We must clear the error counters.
-+ * These registers are cleared on read,
-+ * so we may pass a useless variable to store the value.
-+ */
-+ rt2800_register_read(rt2x00dev, RX_STA_CNT0, &reg);
-+ rt2800_register_read(rt2x00dev, RX_STA_CNT1, &reg);
-+ rt2800_register_read(rt2x00dev, RX_STA_CNT2, &reg);
-+ rt2800_register_read(rt2x00dev, TX_STA_CNT0, &reg);
-+ rt2800_register_read(rt2x00dev, TX_STA_CNT1, &reg);
-+ rt2800_register_read(rt2x00dev, TX_STA_CNT2, &reg);
-+
-+ /*
-+ * Setup leadtime for pre tbtt interrupt to 6ms
-+ */
-+ rt2800_register_read(rt2x00dev, INT_TIMER_CFG, &reg);
-+ rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
-+ rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
-+
-+ /*
-+ * Set up channel statistics timer
-+ */
-+ rt2800_register_read(rt2x00dev, CH_TIME_CFG, &reg);
-+ rt2x00_set_field32(&reg, CH_TIME_CFG_EIFS_BUSY, 1);
-+ rt2x00_set_field32(&reg, CH_TIME_CFG_NAV_BUSY, 1);
-+ rt2x00_set_field32(&reg, CH_TIME_CFG_RX_BUSY, 1);
-+ rt2x00_set_field32(&reg, CH_TIME_CFG_TX_BUSY, 1);
-+ rt2x00_set_field32(&reg, CH_TIME_CFG_TMR_EN, 1);
-+ rt2800_register_write(rt2x00dev, CH_TIME_CFG, reg);
-+
-+ return 0;
-+}
-+
-+static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
-+{
-+ unsigned int i;
-+ u32 reg;
-+
-+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-+ rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, &reg);
-+ if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY))
-+ return 0;
-+
-+ udelay(REGISTER_BUSY_DELAY);
-+ }
-+
-+ rt2x00_err(rt2x00dev, "BBP/RF register access failed, aborting\n");
-+ return -EACCES;
-+}
-+
-+static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
-+{
-+ unsigned int i;
-+ u8 value;
-+
-+ /*
-+ * BBP was enabled after firmware was loaded,
-+ * but we need to reactivate it now.
-+ */
-+ rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
-+ rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
-+ msleep(1);
-+
-+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-+ rt2800_bbp_read(rt2x00dev, 0, &value);
-+ if ((value != 0xff) && (value != 0x00))
-+ return 0;
-+ udelay(REGISTER_BUSY_DELAY);
-+ }
-+
-+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
-+ return -EACCES;
-+}
-+
-+static void rt2800_bbp4_mac_if_ctrl(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 value;
-+
-+ rt2800_bbp_read(rt2x00dev, 4, &value);
-+ rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
-+ rt2800_bbp_write(rt2x00dev, 4, value);
-+}
-+
-+static void rt2800_init_freq_calibration(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 142, 1);
-+ rt2800_bbp_write(rt2x00dev, 143, 57);
-+}
-+
-+static void rt2800_init_bbp_5592_glrt(struct rt2x00_dev *rt2x00dev)
-+{
-+ const u8 glrt_table[] = {
-+ 0xE0, 0x1F, 0X38, 0x32, 0x08, 0x28, 0x19, 0x0A, 0xFF, 0x00, /* 128 ~ 137 */
-+ 0x16, 0x10, 0x10, 0x0B, 0x36, 0x2C, 0x26, 0x24, 0x42, 0x36, /* 138 ~ 147 */
-+ 0x30, 0x2D, 0x4C, 0x46, 0x3D, 0x40, 0x3E, 0x42, 0x3D, 0x40, /* 148 ~ 157 */
-+ 0X3C, 0x34, 0x2C, 0x2F, 0x3C, 0x35, 0x2E, 0x2A, 0x49, 0x41, /* 158 ~ 167 */
-+ 0x36, 0x31, 0x30, 0x30, 0x0E, 0x0D, 0x28, 0x21, 0x1C, 0x16, /* 168 ~ 177 */
-+ 0x50, 0x4A, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, /* 178 ~ 187 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 188 ~ 197 */
-+ 0x00, 0x00, 0x7D, 0x14, 0x32, 0x2C, 0x36, 0x4C, 0x43, 0x2C, /* 198 ~ 207 */
-+ 0x2E, 0x36, 0x30, 0x6E, /* 208 ~ 211 */
-+ };
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(glrt_table); i++) {
-+ rt2800_bbp_write(rt2x00dev, 195, 128 + i);
-+ rt2800_bbp_write(rt2x00dev, 196, glrt_table[i]);
-+ }
-+};
-+
-+static void rt2800_init_bbp_early(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2C);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+ rt2800_bbp_write(rt2x00dev, 68, 0x0B);
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x37);
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6A);
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 103, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+}
-+
-+static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev)
-+{
-+ u16 eeprom;
-+ u8 value;
-+
-+ rt2800_bbp_read(rt2x00dev, 138, &value);
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
-+ value |= 0x20;
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
-+ value &= ~0x02;
-+ rt2800_bbp_write(rt2x00dev, 138, value);
-+}
-+
-+static void rt2800_init_bbp_305x_soc(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
-+
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 78, 0x0e);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x08);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x01);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+}
-+
-+static void rt2800_init_bbp_28xx(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
-+ rt2800_bbp_write(rt2x00dev, 69, 0x16);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x12);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
-+ }
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 81, 0x37);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-+
-+ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
-+ rt2800_bbp_write(rt2x00dev, 84, 0x19);
-+ else
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 103, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+}
-+
-+static void rt2800_init_bbp_30xx(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 79, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x05);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x33);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
-+
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) ||
-+ rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
-+ rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E))
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+ else
-+ rt2800_bbp_write(rt2x00dev, 103, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3071) ||
-+ rt2x00_rt(rt2x00dev, RT3090))
-+ rt2800_disable_unused_dac_adc(rt2x00dev);
-+}
-+
-+static void rt2800_init_bbp_3290(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 value;
-+
-+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
-+
-+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
-+
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 68, 0x0b);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 75, 0x46);
-+ rt2800_bbp_write(rt2x00dev, 76, 0x28);
-+
-+ rt2800_bbp_write(rt2x00dev, 77, 0x58);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 74, 0x0b);
-+ rt2800_bbp_write(rt2x00dev, 79, 0x18);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x09);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x33);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x7a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x9a);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
-+
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+
-+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x1c);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x03);
-+
-+ rt2800_bbp_write(rt2x00dev, 128, 0x12);
-+
-+ rt2800_bbp_write(rt2x00dev, 67, 0x24);
-+ rt2800_bbp_write(rt2x00dev, 143, 0x04);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x99);
-+ rt2800_bbp_write(rt2x00dev, 150, 0x30);
-+ rt2800_bbp_write(rt2x00dev, 151, 0x2e);
-+ rt2800_bbp_write(rt2x00dev, 152, 0x20);
-+ rt2800_bbp_write(rt2x00dev, 153, 0x34);
-+ rt2800_bbp_write(rt2x00dev, 154, 0x40);
-+ rt2800_bbp_write(rt2x00dev, 155, 0x3b);
-+ rt2800_bbp_write(rt2x00dev, 253, 0x04);
-+
-+ rt2800_bbp_read(rt2x00dev, 47, &value);
-+ rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1);
-+ rt2800_bbp_write(rt2x00dev, 47, value);
-+
-+ /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */
-+ rt2800_bbp_read(rt2x00dev, 3, &value);
-+ rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1);
-+ rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1);
-+ rt2800_bbp_write(rt2x00dev, 3, value);
-+}
-+
-+static void rt2800_init_bbp_3352(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 3, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 4, 0x50);
-+
-+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
-+
-+ rt2800_bbp_write(rt2x00dev, 47, 0x48);
-+
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 68, 0x0b);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 75, 0x46);
-+ rt2800_bbp_write(rt2x00dev, 76, 0x28);
-+
-+ rt2800_bbp_write(rt2x00dev, 77, 0x59);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 78, 0x0e);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x08);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x37);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 88, 0x90);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
-+
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+
-+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x34);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x05);
-+
-+ rt2800_bbp_write(rt2x00dev, 120, 0x50);
-+
-+ rt2800_bbp_write(rt2x00dev, 137, 0x0f);
-+
-+ rt2800_bbp_write(rt2x00dev, 163, 0xbd);
-+ /* Set ITxBF timeout to 0x9c40=1000msec */
-+ rt2800_bbp_write(rt2x00dev, 179, 0x02);
-+ rt2800_bbp_write(rt2x00dev, 180, 0x00);
-+ rt2800_bbp_write(rt2x00dev, 182, 0x40);
-+ rt2800_bbp_write(rt2x00dev, 180, 0x01);
-+ rt2800_bbp_write(rt2x00dev, 182, 0x9c);
-+ rt2800_bbp_write(rt2x00dev, 179, 0x00);
-+ /* Reprogram the inband interface to put right values in RXWI */
-+ rt2800_bbp_write(rt2x00dev, 142, 0x04);
-+ rt2800_bbp_write(rt2x00dev, 143, 0x3b);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x06);
-+ rt2800_bbp_write(rt2x00dev, 143, 0xa0);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x07);
-+ rt2800_bbp_write(rt2x00dev, 143, 0xa1);
-+ rt2800_bbp_write(rt2x00dev, 142, 0x08);
-+ rt2800_bbp_write(rt2x00dev, 143, 0xa2);
-+
-+ rt2800_bbp_write(rt2x00dev, 148, 0xc8);
-+}
-+
-+static void rt2800_init_bbp_3390(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 79, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x05);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x33);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
-+
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E))
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+ else
-+ rt2800_bbp_write(rt2x00dev, 103, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+
-+ rt2800_disable_unused_dac_adc(rt2x00dev);
-+}
-+
-+static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
-+
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 79, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x05);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x33);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
-+
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
-+
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+
-+ rt2800_disable_unused_dac_adc(rt2x00dev);
-+}
-+
-+static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
-+{
-+ int ant, div_mode;
-+ u16 eeprom;
-+ u8 value;
-+
-+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
-+
-+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
-+
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
-+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
-+
-+ rt2800_bbp_write(rt2x00dev, 68, 0x0b);
-+
-+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 75, 0x46);
-+ rt2800_bbp_write(rt2x00dev, 76, 0x28);
-+
-+ rt2800_bbp_write(rt2x00dev, 77, 0x59);
-+
-+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-+
-+ rt2800_bbp_write(rt2x00dev, 79, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x05);
-+ rt2800_bbp_write(rt2x00dev, 81, 0x33);
-+
-+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
-+
-+ rt2800_bbp_write(rt2x00dev, 83, 0x7a);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x9a);
-+
-+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5392))
-+ rt2800_bbp_write(rt2x00dev, 88, 0x90);
-+
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+
-+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5392)) {
-+ rt2800_bbp_write(rt2x00dev, 95, 0x9a);
-+ rt2800_bbp_write(rt2x00dev, 98, 0x12);
-+ }
-+
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+
-+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
-+
-+ rt2800_bbp_write(rt2x00dev, 105, 0x3c);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5390))
-+ rt2800_bbp_write(rt2x00dev, 106, 0x03);
-+ else if (rt2x00_rt(rt2x00dev, RT5392))
-+ rt2800_bbp_write(rt2x00dev, 106, 0x12);
-+ else
-+ WARN_ON(1);
-+
-+ rt2800_bbp_write(rt2x00dev, 128, 0x12);
-+
-+ if (rt2x00_rt(rt2x00dev, RT5392)) {
-+ rt2800_bbp_write(rt2x00dev, 134, 0xd0);
-+ rt2800_bbp_write(rt2x00dev, 135, 0xf6);
-+ }
-+
-+ rt2800_disable_unused_dac_adc(rt2x00dev);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+ div_mode = rt2x00_get_field16(eeprom,
-+ EEPROM_NIC_CONF1_ANT_DIVERSITY);
-+ ant = (div_mode == 3) ? 1 : 0;
-+
-+ /* check if this is a Bluetooth combo card */
-+ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
-+ u32 reg;
-+
-+ rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_DIR3, 0);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_DIR6, 0);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL3, 0);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL6, 0);
-+ if (ant == 0)
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL3, 1);
-+ else if (ant == 1)
-+ rt2x00_set_field32(&reg, GPIO_CTRL_VAL6, 1);
-+ rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
-+ }
-+
-+ /* This chip has hardware antenna diversity*/
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) {
-+ rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */
-+ rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */
-+ rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */
-+ }
-+
-+ rt2800_bbp_read(rt2x00dev, 152, &value);
-+ if (ant == 0)
-+ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1);
-+ else
-+ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0);
-+ rt2800_bbp_write(rt2x00dev, 152, value);
-+
-+ rt2800_init_freq_calibration(rt2x00dev);
-+}
-+
-+static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev)
-+{
-+ int ant, div_mode;
-+ u16 eeprom;
-+ u8 value;
-+
-+ rt2800_init_bbp_early(rt2x00dev);
-+
-+ rt2800_bbp_read(rt2x00dev, 105, &value);
-+ rt2x00_set_field8(&value, BBP105_MLD,
-+ rt2x00dev->default_ant.rx_chain_num == 2);
-+ rt2800_bbp_write(rt2x00dev, 105, value);
-+
-+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
-+
-+ rt2800_bbp_write(rt2x00dev, 20, 0x06);
-+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
-+ rt2800_bbp_write(rt2x00dev, 65, 0x2C);
-+ rt2800_bbp_write(rt2x00dev, 68, 0xDD);
-+ rt2800_bbp_write(rt2x00dev, 69, 0x1A);
-+ rt2800_bbp_write(rt2x00dev, 70, 0x05);
-+ rt2800_bbp_write(rt2x00dev, 73, 0x13);
-+ rt2800_bbp_write(rt2x00dev, 74, 0x0F);
-+ rt2800_bbp_write(rt2x00dev, 75, 0x4F);
-+ rt2800_bbp_write(rt2x00dev, 76, 0x28);
-+ rt2800_bbp_write(rt2x00dev, 77, 0x59);
-+ rt2800_bbp_write(rt2x00dev, 84, 0x9A);
-+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
-+ rt2800_bbp_write(rt2x00dev, 88, 0x90);
-+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
-+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
-+ rt2800_bbp_write(rt2x00dev, 95, 0x9a);
-+ rt2800_bbp_write(rt2x00dev, 98, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 103, 0xC0);
-+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
-+ /* FIXME BBP105 owerwrite */
-+ rt2800_bbp_write(rt2x00dev, 105, 0x3C);
-+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
-+ rt2800_bbp_write(rt2x00dev, 128, 0x12);
-+ rt2800_bbp_write(rt2x00dev, 134, 0xD0);
-+ rt2800_bbp_write(rt2x00dev, 135, 0xF6);
-+ rt2800_bbp_write(rt2x00dev, 137, 0x0F);
-+
-+ /* Initialize GLRT (Generalized Likehood Radio Test) */
-+ rt2800_init_bbp_5592_glrt(rt2x00dev);
-+
-+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+ div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY);
-+ ant = (div_mode == 3) ? 1 : 0;
-+ rt2800_bbp_read(rt2x00dev, 152, &value);
-+ if (ant == 0) {
-+ /* Main antenna */
-+ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1);
-+ } else {
-+ /* Auxiliary antenna */
-+ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0);
-+ }
-+ rt2800_bbp_write(rt2x00dev, 152, value);
-+
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) {
-+ rt2800_bbp_read(rt2x00dev, 254, &value);
-+ rt2x00_set_field8(&value, BBP254_BIT7, 1);
-+ rt2800_bbp_write(rt2x00dev, 254, value);
-+ }
-+
-+ rt2800_init_freq_calibration(rt2x00dev);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x19);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C))
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+}
-+
-+static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
-+{
-+ unsigned int i;
-+ u16 eeprom;
-+ u8 reg_id;
-+ u8 value;
-+
-+ if (rt2800_is_305x_soc(rt2x00dev))
-+ rt2800_init_bbp_305x_soc(rt2x00dev);
-+
-+ switch (rt2x00dev->chip.rt) {
-+ case RT2860:
-+ case RT2872:
-+ case RT2883:
-+ rt2800_init_bbp_28xx(rt2x00dev);
-+ break;
-+ case RT3070:
-+ case RT3071:
-+ case RT3090:
-+ rt2800_init_bbp_30xx(rt2x00dev);
-+ break;
-+ case RT3290:
-+ rt2800_init_bbp_3290(rt2x00dev);
-+ break;
-+ case RT3352:
-+ rt2800_init_bbp_3352(rt2x00dev);
-+ break;
-+ case RT3390:
-+ rt2800_init_bbp_3390(rt2x00dev);
-+ break;
-+ case RT3572:
-+ rt2800_init_bbp_3572(rt2x00dev);
-+ break;
-+ case RT5390:
-+ case RT5392:
-+ rt2800_init_bbp_53xx(rt2x00dev);
-+ break;
-+ case RT5592:
-+ rt2800_init_bbp_5592(rt2x00dev);
-+ return;
-+ }
-+
-+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
-+
-+ if (eeprom != 0xffff && eeprom != 0x0000) {
-+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
-+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
-+ rt2800_bbp_write(rt2x00dev, reg_id, value);
-+ }
-+ }
-+}
-+
-+static void rt2800_led_open_drain_enable(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+
-+ rt2800_register_read(rt2x00dev, OPT_14_CSR, &reg);
-+ rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
-+ rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
-+}
-+
-+static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40,
-+ u8 filter_target)
-+{
-+ unsigned int i;
-+ u8 bbp;
-+ u8 rfcsr;
-+ u8 passband;
-+ u8 stopband;
-+ u8 overtuned = 0;
-+ u8 rfcsr24 = (bw40) ? 0x27 : 0x07;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24);
-+
-+ rt2800_bbp_read(rt2x00dev, 4, &bbp);
-+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40);
-+ rt2800_bbp_write(rt2x00dev, 4, bbp);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR31_RX_H20M, bw40);
-+ rt2800_rfcsr_write(rt2x00dev, 31, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
-+
-+ /*
-+ * Set power & frequency of passband test tone
-+ */
-+ rt2800_bbp_write(rt2x00dev, 24, 0);
-+
-+ for (i = 0; i < 100; i++) {
-+ rt2800_bbp_write(rt2x00dev, 25, 0x90);
-+ msleep(1);
-+
-+ rt2800_bbp_read(rt2x00dev, 55, &passband);
-+ if (passband)
-+ break;
-+ }
-+
-+ /*
-+ * Set power & frequency of stopband test tone
-+ */
-+ rt2800_bbp_write(rt2x00dev, 24, 0x06);
-+
-+ for (i = 0; i < 100; i++) {
-+ rt2800_bbp_write(rt2x00dev, 25, 0x90);
-+ msleep(1);
-+
-+ rt2800_bbp_read(rt2x00dev, 55, &stopband);
-+
-+ if ((passband - stopband) <= filter_target) {
-+ rfcsr24++;
-+ overtuned += ((passband - stopband) == filter_target);
-+ } else
-+ break;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24);
-+ }
-+
-+ rfcsr24 -= !!overtuned;
-+
-+ rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24);
-+ return rfcsr24;
-+}
-+
-+static void rt2800_rf_init_calibration(struct rt2x00_dev *rt2x00dev,
-+ const unsigned int rf_reg)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rfcsr_read(rt2x00dev, rf_reg, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, FIELD8(0x80), 1);
-+ rt2800_rfcsr_write(rt2x00dev, rf_reg, rfcsr);
-+ msleep(1);
-+ rt2x00_set_field8(&rfcsr, FIELD8(0x80), 0);
-+ rt2800_rfcsr_write(rt2x00dev, rf_reg, rfcsr);
-+}
-+
-+static void rt2800_rx_filter_calibration(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
-+ u8 filter_tgt_bw20;
-+ u8 filter_tgt_bw40;
-+ u8 rfcsr, bbp;
-+
-+ /*
-+ * TODO: sync filter_tgt values with vendor driver
-+ */
-+ if (rt2x00_rt(rt2x00dev, RT3070)) {
-+ filter_tgt_bw20 = 0x16;
-+ filter_tgt_bw40 = 0x19;
-+ } else {
-+ filter_tgt_bw20 = 0x13;
-+ filter_tgt_bw40 = 0x15;
-+ }
-+
-+ drv_data->calibration_bw20 =
-+ rt2800_init_rx_filter(rt2x00dev, false, filter_tgt_bw20);
-+ drv_data->calibration_bw40 =
-+ rt2800_init_rx_filter(rt2x00dev, true, filter_tgt_bw40);
-+
-+ /*
-+ * Save BBP 25 & 26 values for later use in channel switching (for 3052)
-+ */
-+ rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25);
-+ rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26);
-+
-+ /*
-+ * Set back to initial state
-+ */
-+ rt2800_bbp_write(rt2x00dev, 24, 0);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
-+
-+ /*
-+ * Set BBP back to BW20
-+ */
-+ rt2800_bbp_read(rt2x00dev, 4, &bbp);
-+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
-+ rt2800_bbp_write(rt2x00dev, 4, bbp);
-+}
-+
-+static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
-+ u8 min_gain, rfcsr, bbp;
-+ u16 eeprom;
-+
-+ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
-+
-+ rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
-+ if (rt2x00_rt(rt2x00dev, RT3070) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
-+ if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
-+ rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
-+ }
-+
-+ min_gain = rt2x00_rt(rt2x00dev, RT3070) ? 1 : 2;
-+ if (drv_data->txmixer_gain_24g >= min_gain) {
-+ rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN,
-+ drv_data->txmixer_gain_24g);
-+ }
-+
-+ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3090)) {
-+ /* Turn off unused DAC1 and ADC1 to reduce power consumption */
-+ rt2800_bbp_read(rt2x00dev, 138, &bbp);
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
-+ rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
-+ rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
-+ rt2800_bbp_write(rt2x00dev, 138, bbp);
-+ }
-+
-+ if (rt2x00_rt(rt2x00dev, RT3070)) {
-+ rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr);
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F))
-+ rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3);
-+ else
-+ rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR27_R2, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR27_R3, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR27_R4, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
-+ } else if (rt2x00_rt(rt2x00dev, RT3071) ||
-+ rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3390)) {
-+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
-+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 15, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
-+ }
-+}
-+
-+static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 reg;
-+ u16 eeprom;
-+
-+ /* Turn off unused DAC1 and ADC1 to reduce power consumption */
-+ rt2800_bbp_read(rt2x00dev, 138, &reg);
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
-+ rt2x00_set_field8(&reg, BBP138_RX_ADC1, 0);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
-+ rt2x00_set_field8(&reg, BBP138_TX_DAC1, 1);
-+ rt2800_bbp_write(rt2x00dev, 138, reg);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 38, &reg);
-+ rt2x00_set_field8(&reg, RFCSR38_RX_LO1_EN, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 38, reg);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 39, &reg);
-+ rt2x00_set_field8(&reg, RFCSR39_RX_LO2_EN, 0);
-+ rt2800_rfcsr_write(rt2x00dev, 39, reg);
-+
-+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 30, &reg);
-+ rt2x00_set_field8(&reg, RFCSR30_RX_VCM, 2);
-+ rt2800_rfcsr_write(rt2x00dev, 30, reg);
-+}
-+
-+static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_rf_init_calibration(rt2x00dev, 30);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-+ rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
-+}
-+
-+static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 rfcsr;
-+ u16 eeprom;
-+ u32 reg;
-+
-+ /* XXX vendor driver do this only for 3070 */
-+ rt2800_rf_init_calibration(rt2x00dev, 30);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-+ rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
-+
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
-+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
-+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
-+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
-+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
-+ } else if (rt2x00_rt(rt2x00dev, RT3071) ||
-+ rt2x00_rt(rt2x00dev, RT3090)) {
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
-+
-+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
-+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
-+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
-+ else
-+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
-+ }
-+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
-+
-+ rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
-+ rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
-+ rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
-+ }
-+
-+ rt2800_rx_filter_calibration(rt2x00dev);
-+
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
-+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E))
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-+
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 rfcsr;
-+
-+ rt2800_rf_init_calibration(rt2x00dev, 2);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
-+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-+ rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3);
-+ rt2800_rfcsr_write(rt2x00dev, 29, rfcsr);
-+
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_rf_init_calibration(rt2x00dev, 30);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
-+ rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
-+ rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
-+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
-+ rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
-+
-+ rt2800_rx_filter_calibration(rt2x00dev);
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+
-+ rt2800_rf_init_calibration(rt2x00dev, 30);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
-+ rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
-+ rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
-+
-+ rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
-+ rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
-+ rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
-+
-+ rt2800_rx_filter_calibration(rt2x00dev);
-+
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E))
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-+
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
-+{
-+ u8 rfcsr;
-+ u32 reg;
-+
-+ rt2800_rf_init_calibration(rt2x00dev, 30);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
-+ rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
-+ rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
-+ rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
-+
-+ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
-+ rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
-+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
-+
-+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
-+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
-+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
-+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
-+ msleep(1);
-+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
-+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
-+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
-+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
-+
-+ rt2800_rx_filter_calibration(rt2x00dev);
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_rf_init_calibration(rt2x00dev, 2);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-+
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
-+ rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
-+ else
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
-+
-+ rt2800_normal_mode_setup_5xxx(rt2x00dev);
-+
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_rf_init_calibration(rt2x00dev, 2);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-+ rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
-+ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
-+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-+ rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
-+ rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
-+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-+ rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
-+ rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
-+ rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
-+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
-+ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-+ rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
-+ rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
-+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-+ rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-+ rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
-+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-+ rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
-+ rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
-+ rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
-+ rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
-+ rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-+ rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
-+ rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
-+ rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
-+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-+ rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
-+ rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
-+ rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
-+
-+ rt2800_normal_mode_setup_5xxx(rt2x00dev);
-+
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev)
-+{
-+ rt2800_rf_init_calibration(rt2x00dev, 30);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 1, 0x3F);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
-+ rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 6, 0xE4);
-+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-+ rt2800_rfcsr_write(rt2x00dev, 19, 0x4D);
-+ rt2800_rfcsr_write(rt2x00dev, 20, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 21, 0x8D);
-+ rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-+ rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
-+ rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0C);
-+ rt2800_rfcsr_write(rt2x00dev, 53, 0x22);
-+ rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
-+
-+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-+ msleep(1);
-+
-+ rt2800_adjust_freq_offset(rt2x00dev);
-+
-+ /* Enable DC filter */
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C))
-+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
-+
-+ rt2800_normal_mode_setup_5xxx(rt2x00dev);
-+
-+ if (rt2x00_rt_rev_lt(rt2x00dev, RT5592, REV_RT5592C))
-+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-+
-+ rt2800_led_open_drain_enable(rt2x00dev);
-+}
-+
-+static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
-+{
-+ if (rt2800_is_305x_soc(rt2x00dev)) {
-+ rt2800_init_rfcsr_305x_soc(rt2x00dev);
-+ return;
-+ }
-+
-+ switch (rt2x00dev->chip.rt) {
-+ case RT3070:
-+ case RT3071:
-+ case RT3090:
-+ rt2800_init_rfcsr_30xx(rt2x00dev);
-+ break;
-+ case RT3290:
-+ rt2800_init_rfcsr_3290(rt2x00dev);
-+ break;
-+ case RT3352:
-+ rt2800_init_rfcsr_3352(rt2x00dev);
-+ break;
-+ case RT3390:
-+ rt2800_init_rfcsr_3390(rt2x00dev);
-+ break;
-+ case RT3572:
-+ rt2800_init_rfcsr_3572(rt2x00dev);
-+ break;
-+ case RT5390:
-+ rt2800_init_rfcsr_5390(rt2x00dev);
-+ break;
-+ case RT5392:
-+ rt2800_init_rfcsr_5392(rt2x00dev);
-+ break;
-+ case RT5592:
-+ rt2800_init_rfcsr_5592(rt2x00dev);
-+ break;
-+ }
-+}
-+
-+int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+ u16 word;
-+
-+ /*
-+ * Initialize all registers.
-+ */
-+ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
-+ rt2800_init_registers(rt2x00dev)))
-+ return -EIO;
-+
-+ if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev)))
-+ return -EIO;
-+
-+ /*
-+ * Send signal to firmware during boot time.
-+ */
-+ rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
-+ rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
-+ if (rt2x00_is_usb(rt2x00dev))
-+ rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
-+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-+ msleep(1);
-+
-+ if (unlikely(rt2800_wait_bbp_ready(rt2x00dev)))
-+ return -EIO;
-+
-+ rt2800_init_bbp(rt2x00dev);
-+ rt2800_init_rfcsr(rt2x00dev);
-+
-+ if (rt2x00_is_usb(rt2x00dev) &&
-+ (rt2x00_rt(rt2x00dev, RT3070) ||
-+ rt2x00_rt(rt2x00dev, RT3071) ||
-+ rt2x00_rt(rt2x00dev, RT3572))) {
-+ udelay(200);
-+ rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
-+ udelay(10);
-+ }
-+
-+ /*
-+ * Enable RX.
-+ */
-+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
-+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-+
-+ udelay(50);
-+
-+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
-+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-+ rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-+
-+ /*
-+ * Initialize LED control
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word);
-+ rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff,
-+ word & 0xff, (word >> 8) & 0xff);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word);
-+ rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff,
-+ word & 0xff, (word >> 8) & 0xff);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word);
-+ rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff,
-+ word & 0xff, (word >> 8) & 0xff);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_enable_radio);
-+
-+void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+
-+ rt2800_disable_wpdma(rt2x00dev);
-+
-+ /* Wait for DMA, ignore error */
-+ rt2800_wait_wpdma_ready(rt2x00dev);
-+
-+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 0);
-+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
-+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_disable_radio);
-+
-+int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+ u16 efuse_ctrl_reg;
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290))
-+ efuse_ctrl_reg = EFUSE_CTRL_3290;
-+ else
-+ efuse_ctrl_reg = EFUSE_CTRL;
-+
-+ rt2800_register_read(rt2x00dev, efuse_ctrl_reg, &reg);
-+ return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT);
-+}
-+EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
-+
-+static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
-+{
-+ u32 reg;
-+ u16 efuse_ctrl_reg;
-+ u16 efuse_data0_reg;
-+ u16 efuse_data1_reg;
-+ u16 efuse_data2_reg;
-+ u16 efuse_data3_reg;
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290)) {
-+ efuse_ctrl_reg = EFUSE_CTRL_3290;
-+ efuse_data0_reg = EFUSE_DATA0_3290;
-+ efuse_data1_reg = EFUSE_DATA1_3290;
-+ efuse_data2_reg = EFUSE_DATA2_3290;
-+ efuse_data3_reg = EFUSE_DATA3_3290;
-+ } else {
-+ efuse_ctrl_reg = EFUSE_CTRL;
-+ efuse_data0_reg = EFUSE_DATA0;
-+ efuse_data1_reg = EFUSE_DATA1;
-+ efuse_data2_reg = EFUSE_DATA2;
-+ efuse_data3_reg = EFUSE_DATA3;
-+ }
-+ mutex_lock(&rt2x00dev->csr_mutex);
-+
-+ rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, &reg);
-+ rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
-+ rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
-+ rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
-+ rt2800_register_write_lock(rt2x00dev, efuse_ctrl_reg, reg);
-+
-+ /* Wait until the EEPROM has been loaded */
-+ rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, &reg);
-+ /* Apparently the data is read from end to start */
-+ rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, &reg);
-+ /* The returned value is in CPU order, but eeprom is le */
-+ *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
-+ rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, &reg);
-+ *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
-+ rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, &reg);
-+ *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
-+ rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, &reg);
-+ *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
-+
-+ mutex_unlock(&rt2x00dev->csr_mutex);
-+}
-+
-+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
-+ rt2800_efuse_read(rt2x00dev, i);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
-+
-+static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
-+ u16 word;
-+ u8 *mac;
-+ u8 default_lna_gain;
-+ int retval;
-+
-+ /*
-+ * Read the EEPROM.
-+ */
-+ retval = rt2800_read_eeprom(rt2x00dev);
-+ if (retval)
-+ return retval;
-+
-+ /*
-+ * Start validation of the data that has been read.
-+ */
-+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
-+ if (!is_valid_ether_addr(mac)) {
-+ eth_random_addr(mac);
-+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
-+ }
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
-+ if (word == 0xffff) {
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
-+ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
-+ } else if (rt2x00_rt(rt2x00dev, RT2860) ||
-+ rt2x00_rt(rt2x00dev, RT2872)) {
-+ /*
-+ * There is a max of 2 RX streams for RT28x0 series
-+ */
-+ if (rt2x00_get_field16(word, EEPROM_NIC_CONF0_RXPATH) > 2)
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
-+ }
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word);
-+ if (word == 0xffff) {
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_CARDBUS_ACCEL, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_2G, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_5G, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_WPS_PBC, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_2G, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_5G, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BROADBAND_EXT_LNA, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_ANT_DIVERSITY, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_INTERNAL_TX_ALC, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0);
-+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
-+ rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
-+ }
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
-+ if ((word & 0x00ff) == 0x00ff) {
-+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
-+ rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word);
-+ }
-+ if ((word & 0xff00) == 0xff00) {
-+ rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
-+ LED_MODE_TXRX_ACTIVITY);
-+ rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
-+ rt2x00_eeprom_dbg(rt2x00dev, "Led Mode: 0x%04x\n", word);
-+ }
-+
-+ /*
-+ * During the LNA validation we are going to use
-+ * lna0 as correct value. Note that EEPROM_LNA
-+ * is never validated.
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
-+ default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
-+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
-+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word);
-+ if ((word & 0x00ff) != 0x00ff) {
-+ drv_data->txmixer_gain_24g =
-+ rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL);
-+ } else {
-+ drv_data->txmixer_gain_24g = 0;
-+ }
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
-+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
-+ if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
-+ rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
-+ default_lna_gain);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word);
-+ if ((word & 0x00ff) != 0x00ff) {
-+ drv_data->txmixer_gain_5g =
-+ rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL);
-+ } else {
-+ drv_data->txmixer_gain_5g = 0;
-+ }
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
-+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
-+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
-+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
-+ if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
-+ rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
-+ rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
-+ default_lna_gain);
-+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
-+
-+ return 0;
-+}
-+
-+static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
-+{
-+ u16 value;
-+ u16 eeprom;
-+ u16 rf;
-+
-+ /*
-+ * Read EEPROM word for configuration.
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
-+
-+ /*
-+ * Identify RF chipset by EEPROM value
-+ * RT28xx/RT30xx: defined in "EEPROM_NIC_CONF0_RF_TYPE" field
-+ * RT53xx: defined in "EEPROM_CHIP_ID" field
-+ */
-+ if (rt2x00_rt(rt2x00dev, RT3290) ||
-+ rt2x00_rt(rt2x00dev, RT5390) ||
-+ rt2x00_rt(rt2x00dev, RT5392))
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
-+ else
-+ rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
-+
-+ switch (rf) {
-+ case RF2820:
-+ case RF2850:
-+ case RF2720:
-+ case RF2750:
-+ case RF3020:
-+ case RF2020:
-+ case RF3021:
-+ case RF3022:
-+ case RF3052:
-+ case RF3290:
-+ case RF3320:
-+ case RF3322:
-+ case RF5360:
-+ case RF5370:
-+ case RF5372:
-+ case RF5390:
-+ case RF5392:
-+ case RF5592:
-+ break;
-+ default:
-+ rt2x00_err(rt2x00dev, "Invalid RF chipset 0x%04x detected\n",
-+ rf);
-+ return -ENODEV;
-+ }
-+
-+ rt2x00_set_rf(rt2x00dev, rf);
-+
-+ /*
-+ * Identify default antenna configuration.
-+ */
-+ rt2x00dev->default_ant.tx_chain_num =
-+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH);
-+ rt2x00dev->default_ant.rx_chain_num =
-+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH);
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-+
-+ if (rt2x00_rt(rt2x00dev, RT3070) ||
-+ rt2x00_rt(rt2x00dev, RT3090) ||
-+ rt2x00_rt(rt2x00dev, RT3352) ||
-+ rt2x00_rt(rt2x00dev, RT3390)) {
-+ value = rt2x00_get_field16(eeprom,
-+ EEPROM_NIC_CONF1_ANT_DIVERSITY);
-+ switch (value) {
-+ case 0:
-+ case 1:
-+ case 2:
-+ rt2x00dev->default_ant.tx = ANTENNA_A;
-+ rt2x00dev->default_ant.rx = ANTENNA_A;
-+ break;
-+ case 3:
-+ rt2x00dev->default_ant.tx = ANTENNA_A;
-+ rt2x00dev->default_ant.rx = ANTENNA_B;
-+ break;
-+ }
-+ } else {
-+ rt2x00dev->default_ant.tx = ANTENNA_A;
-+ rt2x00dev->default_ant.rx = ANTENNA_A;
-+ }
-+
-+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) {
-+ rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; /* Unused */
-+ rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; /* Unused */
-+ }
-+
-+ /*
-+ * Determine external LNA informations.
-+ */
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
-+ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
-+ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
-+
-+ /*
-+ * Detect if this device has an hardware controlled radio.
-+ */
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
-+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
-+
-+ /*
-+ * Detect if this device has Bluetooth co-existence.
-+ */
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
-+ __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
-+
-+ /*
-+ * Read frequency offset and RF programming sequence.
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
-+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
-+
-+ /*
-+ * Store led settings, for correct led behaviour.
-+ */
-+#ifdef CONFIG_RT2X00_LIB_LEDS
-+ rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
-+ rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
-+ rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
-+
-+ rt2x00dev->led_mcu_reg = eeprom;
-+#endif /* CONFIG_RT2X00_LIB_LEDS */
-+
-+ /*
-+ * Check if support EIRP tx power limit feature.
-+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom);
-+
-+ if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) <
-+ EIRP_MAX_TX_POWER_LIMIT)
-+ __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
-+
-+ return 0;
-+}
-+
-+/*
-+ * RF value list for rt28xx
-+ * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
-+ */
-+static const struct rf_channel rf_vals[] = {
-+ { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
-+ { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
-+ { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
-+ { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
-+ { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
-+ { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
-+ { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
-+ { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
-+ { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
-+ { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
-+ { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
-+ { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
-+ { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
-+ { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
-+
-+ /* 802.11 UNI / HyperLan 2 */
-+ { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
-+ { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
-+ { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
-+ { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
-+ { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
-+ { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
-+ { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
-+ { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
-+ { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
-+ { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
-+ { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
-+ { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
-+
-+ /* 802.11 HyperLan 2 */
-+ { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
-+ { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
-+ { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
-+ { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
-+ { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
-+ { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
-+ { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
-+ { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
-+ { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
-+ { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
-+ { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
-+ { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
-+ { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
-+ { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
-+ { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
-+ { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
-+
-+ /* 802.11 UNII */
-+ { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
-+ { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
-+ { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
-+ { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
-+ { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
-+ { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
-+ { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
-+ { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f },
-+ { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 },
-+ { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 },
-+ { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f },
-+
-+ /* 802.11 Japan */
-+ { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
-+ { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
-+ { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
-+ { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
-+ { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
-+ { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
-+ { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
-+};
-+
-+/*
-+ * RF value list for rt3xxx
-+ * Supports: 2.4 GHz (all) & 5.2 GHz (RF3052)
-+ */
-+static const struct rf_channel rf_vals_3x[] = {
-+ {1, 241, 2, 2 },
-+ {2, 241, 2, 7 },
-+ {3, 242, 2, 2 },
-+ {4, 242, 2, 7 },
-+ {5, 243, 2, 2 },
-+ {6, 243, 2, 7 },
-+ {7, 244, 2, 2 },
-+ {8, 244, 2, 7 },
-+ {9, 245, 2, 2 },
-+ {10, 245, 2, 7 },
-+ {11, 246, 2, 2 },
-+ {12, 246, 2, 7 },
-+ {13, 247, 2, 2 },
-+ {14, 248, 2, 4 },
-+
-+ /* 802.11 UNI / HyperLan 2 */
-+ {36, 0x56, 0, 4},
-+ {38, 0x56, 0, 6},
-+ {40, 0x56, 0, 8},
-+ {44, 0x57, 0, 0},
-+ {46, 0x57, 0, 2},
-+ {48, 0x57, 0, 4},
-+ {52, 0x57, 0, 8},
-+ {54, 0x57, 0, 10},
-+ {56, 0x58, 0, 0},
-+ {60, 0x58, 0, 4},
-+ {62, 0x58, 0, 6},
-+ {64, 0x58, 0, 8},
-+
-+ /* 802.11 HyperLan 2 */
-+ {100, 0x5b, 0, 8},
-+ {102, 0x5b, 0, 10},
-+ {104, 0x5c, 0, 0},
-+ {108, 0x5c, 0, 4},
-+ {110, 0x5c, 0, 6},
-+ {112, 0x5c, 0, 8},
-+ {116, 0x5d, 0, 0},
-+ {118, 0x5d, 0, 2},
-+ {120, 0x5d, 0, 4},
-+ {124, 0x5d, 0, 8},
-+ {126, 0x5d, 0, 10},
-+ {128, 0x5e, 0, 0},
-+ {132, 0x5e, 0, 4},
-+ {134, 0x5e, 0, 6},
-+ {136, 0x5e, 0, 8},
-+ {140, 0x5f, 0, 0},
-+
-+ /* 802.11 UNII */
-+ {149, 0x5f, 0, 9},
-+ {151, 0x5f, 0, 11},
-+ {153, 0x60, 0, 1},
-+ {157, 0x60, 0, 5},
-+ {159, 0x60, 0, 7},
-+ {161, 0x60, 0, 9},
-+ {165, 0x61, 0, 1},
-+ {167, 0x61, 0, 3},
-+ {169, 0x61, 0, 5},
-+ {171, 0x61, 0, 7},
-+ {173, 0x61, 0, 9},
-+};
-+
-+static const struct rf_channel rf_vals_5592_xtal20[] = {
-+ /* Channel, N, K, mod, R */
-+ {1, 482, 4, 10, 3},
-+ {2, 483, 4, 10, 3},
-+ {3, 484, 4, 10, 3},
-+ {4, 485, 4, 10, 3},
-+ {5, 486, 4, 10, 3},
-+ {6, 487, 4, 10, 3},
-+ {7, 488, 4, 10, 3},
-+ {8, 489, 4, 10, 3},
-+ {9, 490, 4, 10, 3},
-+ {10, 491, 4, 10, 3},
-+ {11, 492, 4, 10, 3},
-+ {12, 493, 4, 10, 3},
-+ {13, 494, 4, 10, 3},
-+ {14, 496, 8, 10, 3},
-+ {36, 172, 8, 12, 1},
-+ {38, 173, 0, 12, 1},
-+ {40, 173, 4, 12, 1},
-+ {42, 173, 8, 12, 1},
-+ {44, 174, 0, 12, 1},
-+ {46, 174, 4, 12, 1},
-+ {48, 174, 8, 12, 1},
-+ {50, 175, 0, 12, 1},
-+ {52, 175, 4, 12, 1},
-+ {54, 175, 8, 12, 1},
-+ {56, 176, 0, 12, 1},
-+ {58, 176, 4, 12, 1},
-+ {60, 176, 8, 12, 1},
-+ {62, 177, 0, 12, 1},
-+ {64, 177, 4, 12, 1},
-+ {100, 183, 4, 12, 1},
-+ {102, 183, 8, 12, 1},
-+ {104, 184, 0, 12, 1},
-+ {106, 184, 4, 12, 1},
-+ {108, 184, 8, 12, 1},
-+ {110, 185, 0, 12, 1},
-+ {112, 185, 4, 12, 1},
-+ {114, 185, 8, 12, 1},
-+ {116, 186, 0, 12, 1},
-+ {118, 186, 4, 12, 1},
-+ {120, 186, 8, 12, 1},
-+ {122, 187, 0, 12, 1},
-+ {124, 187, 4, 12, 1},
-+ {126, 187, 8, 12, 1},
-+ {128, 188, 0, 12, 1},
-+ {130, 188, 4, 12, 1},
-+ {132, 188, 8, 12, 1},
-+ {134, 189, 0, 12, 1},
-+ {136, 189, 4, 12, 1},
-+ {138, 189, 8, 12, 1},
-+ {140, 190, 0, 12, 1},
-+ {149, 191, 6, 12, 1},
-+ {151, 191, 10, 12, 1},
-+ {153, 192, 2, 12, 1},
-+ {155, 192, 6, 12, 1},
-+ {157, 192, 10, 12, 1},
-+ {159, 193, 2, 12, 1},
-+ {161, 193, 6, 12, 1},
-+ {165, 194, 2, 12, 1},
-+ {184, 164, 0, 12, 1},
-+ {188, 164, 4, 12, 1},
-+ {192, 165, 8, 12, 1},
-+ {196, 166, 0, 12, 1},
-+};
-+
-+static const struct rf_channel rf_vals_5592_xtal40[] = {
-+ /* Channel, N, K, mod, R */
-+ {1, 241, 2, 10, 3},
-+ {2, 241, 7, 10, 3},
-+ {3, 242, 2, 10, 3},
-+ {4, 242, 7, 10, 3},
-+ {5, 243, 2, 10, 3},
-+ {6, 243, 7, 10, 3},
-+ {7, 244, 2, 10, 3},
-+ {8, 244, 7, 10, 3},
-+ {9, 245, 2, 10, 3},
-+ {10, 245, 7, 10, 3},
-+ {11, 246, 2, 10, 3},
-+ {12, 246, 7, 10, 3},
-+ {13, 247, 2, 10, 3},
-+ {14, 248, 4, 10, 3},
-+ {36, 86, 4, 12, 1},
-+ {38, 86, 6, 12, 1},
-+ {40, 86, 8, 12, 1},
-+ {42, 86, 10, 12, 1},
-+ {44, 87, 0, 12, 1},
-+ {46, 87, 2, 12, 1},
-+ {48, 87, 4, 12, 1},
-+ {50, 87, 6, 12, 1},
-+ {52, 87, 8, 12, 1},
-+ {54, 87, 10, 12, 1},
-+ {56, 88, 0, 12, 1},
-+ {58, 88, 2, 12, 1},
-+ {60, 88, 4, 12, 1},
-+ {62, 88, 6, 12, 1},
-+ {64, 88, 8, 12, 1},
-+ {100, 91, 8, 12, 1},
-+ {102, 91, 10, 12, 1},
-+ {104, 92, 0, 12, 1},
-+ {106, 92, 2, 12, 1},
-+ {108, 92, 4, 12, 1},
-+ {110, 92, 6, 12, 1},
-+ {112, 92, 8, 12, 1},
-+ {114, 92, 10, 12, 1},
-+ {116, 93, 0, 12, 1},
-+ {118, 93, 2, 12, 1},
-+ {120, 93, 4, 12, 1},
-+ {122, 93, 6, 12, 1},
-+ {124, 93, 8, 12, 1},
-+ {126, 93, 10, 12, 1},
-+ {128, 94, 0, 12, 1},
-+ {130, 94, 2, 12, 1},
-+ {132, 94, 4, 12, 1},
-+ {134, 94, 6, 12, 1},
-+ {136, 94, 8, 12, 1},
-+ {138, 94, 10, 12, 1},
-+ {140, 95, 0, 12, 1},
-+ {149, 95, 9, 12, 1},
-+ {151, 95, 11, 12, 1},
-+ {153, 96, 1, 12, 1},
-+ {155, 96, 3, 12, 1},
-+ {157, 96, 5, 12, 1},
-+ {159, 96, 7, 12, 1},
-+ {161, 96, 9, 12, 1},
-+ {165, 97, 1, 12, 1},
-+ {184, 82, 0, 12, 1},
-+ {188, 82, 4, 12, 1},
-+ {192, 82, 8, 12, 1},
-+ {196, 83, 0, 12, 1},
-+};
-+
-+static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct hw_mode_spec *spec = &rt2x00dev->spec;
-+ struct channel_info *info;
-+ char *default_power1;
-+ char *default_power2;
-+ unsigned int i;
-+ u16 eeprom;
-+ u32 reg;
-+
-+ /*
-+ * Disable powersaving as default on PCI devices.
-+ */
-+ if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-+ rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-+
-+ /*
-+ * Initialize all hw fields.
-+ */
-+ rt2x00dev->hw->flags =
-+ IEEE80211_HW_SIGNAL_DBM |
-+ IEEE80211_HW_SUPPORTS_PS |
-+ IEEE80211_HW_PS_NULLFUNC_STACK |
-+ IEEE80211_HW_AMPDU_AGGREGATION |
-+ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-+ IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
-+
-+ /*
-+ * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
-+ * unless we are capable of sending the buffered frames out after the
-+ * DTIM transmission using rt2x00lib_beacondone. This will send out
-+ * multicast and broadcast traffic immediately instead of buffering it
-+ * infinitly and thus dropping it after some time.
-+ */
-+ if (!rt2x00_is_usb(rt2x00dev))
-+ rt2x00dev->hw->flags |=
-+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
-+
-+ SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
-+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
-+ rt2x00_eeprom_addr(rt2x00dev,
-+ EEPROM_MAC_ADDR_0));
-+
-+ /*
-+ * As rt2800 has a global fallback table we cannot specify
-+ * more then one tx rate per frame but since the hw will
-+ * try several rates (based on the fallback table) we should
-+ * initialize max_report_rates to the maximum number of rates
-+ * we are going to try. Otherwise mac80211 will truncate our
-+ * reported tx rates and the rc algortihm will end up with
-+ * incorrect data.
-+ */
-+ rt2x00dev->hw->max_rates = 1;
-+ rt2x00dev->hw->max_report_rates = 7;
-+ rt2x00dev->hw->max_rate_tries = 1;
-+
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
-+
-+ /*
-+ * Initialize hw_mode information.
-+ */
-+ spec->supported_bands = SUPPORT_BAND_2GHZ;
-+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
-+
-+ if (rt2x00_rf(rt2x00dev, RF2820) ||
-+ rt2x00_rf(rt2x00dev, RF2720)) {
-+ spec->num_channels = 14;
-+ spec->channels = rf_vals;
-+ } else if (rt2x00_rf(rt2x00dev, RF2850) ||
-+ rt2x00_rf(rt2x00dev, RF2750)) {
-+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
-+ spec->num_channels = ARRAY_SIZE(rf_vals);
-+ spec->channels = rf_vals;
-+ } else if (rt2x00_rf(rt2x00dev, RF3020) ||
-+ rt2x00_rf(rt2x00dev, RF2020) ||
-+ rt2x00_rf(rt2x00dev, RF3021) ||
-+ rt2x00_rf(rt2x00dev, RF3022) ||
-+ rt2x00_rf(rt2x00dev, RF3290) ||
-+ rt2x00_rf(rt2x00dev, RF3320) ||
-+ rt2x00_rf(rt2x00dev, RF3322) ||
-+ rt2x00_rf(rt2x00dev, RF5360) ||
-+ rt2x00_rf(rt2x00dev, RF5370) ||
-+ rt2x00_rf(rt2x00dev, RF5372) ||
-+ rt2x00_rf(rt2x00dev, RF5390) ||
-+ rt2x00_rf(rt2x00dev, RF5392)) {
-+ spec->num_channels = 14;
-+ spec->channels = rf_vals_3x;
-+ } else if (rt2x00_rf(rt2x00dev, RF3052)) {
-+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
-+ spec->num_channels = ARRAY_SIZE(rf_vals_3x);
-+ spec->channels = rf_vals_3x;
-+ } else if (rt2x00_rf(rt2x00dev, RF5592)) {
-+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
-+
-+ rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX, &reg);
-+ if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) {
-+ spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal40);
-+ spec->channels = rf_vals_5592_xtal40;
-+ } else {
-+ spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal20);
-+ spec->channels = rf_vals_5592_xtal20;
-+ }
-+ }
-+
-+ if (WARN_ON_ONCE(!spec->channels))
-+ return -ENODEV;
-+
-+ /*
-+ * Initialize HT information.
-+ */
-+ if (!rt2x00_rf(rt2x00dev, RF2020))
-+ spec->ht.ht_supported = true;
-+ else
-+ spec->ht.ht_supported = false;
-+
-+ spec->ht.cap =
-+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-+ IEEE80211_HT_CAP_GRN_FLD |
-+ IEEE80211_HT_CAP_SGI_20 |
-+ IEEE80211_HT_CAP_SGI_40;
-+
-+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) >= 2)
-+ spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
-+
-+ spec->ht.cap |=
-+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) <<
-+ IEEE80211_HT_CAP_RX_STBC_SHIFT;
-+
-+ spec->ht.ampdu_factor = 3;
-+ spec->ht.ampdu_density = 4;
-+ spec->ht.mcs.tx_params =
-+ IEEE80211_HT_MCS_TX_DEFINED |
-+ IEEE80211_HT_MCS_TX_RX_DIFF |
-+ ((rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) - 1) <<
-+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
-+
-+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH)) {
-+ case 3:
-+ spec->ht.mcs.rx_mask[2] = 0xff;
-+ case 2:
-+ spec->ht.mcs.rx_mask[1] = 0xff;
-+ case 1:
-+ spec->ht.mcs.rx_mask[0] = 0xff;
-+ spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
-+ break;
-+ }
-+
-+ /*
-+ * Create channel information array
-+ */
-+ info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ spec->channels_info = info;
-+
-+ default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
-+ default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
-+
-+ for (i = 0; i < 14; i++) {
-+ info[i].default_power1 = default_power1[i];
-+ info[i].default_power2 = default_power2[i];
-+ }
-+
-+ if (spec->num_channels > 14) {
-+ default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
-+ default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
-+
-+ for (i = 14; i < spec->num_channels; i++) {
-+ info[i].default_power1 = default_power1[i - 14];
-+ info[i].default_power2 = default_power2[i - 14];
-+ }
-+ }
-+
-+ switch (rt2x00dev->chip.rf) {
-+ case RF2020:
-+ case RF3020:
-+ case RF3021:
-+ case RF3022:
-+ case RF3320:
-+ case RF3052:
-+ case RF3290:
-+ case RF5360:
-+ case RF5370:
-+ case RF5372:
-+ case RF5390:
-+ case RF5392:
-+ __set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+ u32 rt;
-+ u32 rev;
-+
-+ if (rt2x00_rt(rt2x00dev, RT3290))
-+ rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
-+ else
-+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-+
-+ rt = rt2x00_get_field32(reg, MAC_CSR0_CHIPSET);
-+ rev = rt2x00_get_field32(reg, MAC_CSR0_REVISION);
-+
-+ switch (rt) {
-+ case RT2860:
-+ case RT2872:
-+ case RT2883:
-+ case RT3070:
-+ case RT3071:
-+ case RT3090:
-+ case RT3290:
-+ case RT3352:
-+ case RT3390:
-+ case RT3572:
-+ case RT5390:
-+ case RT5392:
-+ case RT5592:
-+ break;
-+ default:
-+ rt2x00_err(rt2x00dev, "Invalid RT chipset 0x%04x, rev %04x detected\n",
-+ rt, rev);
-+ return -ENODEV;
-+ }
-+
-+ rt2x00_set_rt(rt2x00dev, rt, rev);
-+
-+ return 0;
-+}
-+
-+int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
-+{
-+ int retval;
-+ u32 reg;
-+
-+ retval = rt2800_probe_rt(rt2x00dev);
-+ if (retval)
-+ return retval;
-+
-+ /*
-+ * Allocate eeprom data.
-+ */
-+ retval = rt2800_validate_eeprom(rt2x00dev);
-+ if (retval)
-+ return retval;
-+
-+ retval = rt2800_init_eeprom(rt2x00dev);
-+ if (retval)
-+ return retval;
-+
-+ /*
-+ * Enable rfkill polling by setting GPIO direction of the
-+ * rfkill switch GPIO pin correctly.
-+ */
-+ rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
-+ rt2x00_set_field32(&reg, GPIO_CTRL_DIR2, 1);
-+ rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
-+
-+ /*
-+ * Initialize hw specifications.
-+ */
-+ retval = rt2800_probe_hw_mode(rt2x00dev);
-+ if (retval)
-+ return retval;
-+
-+ /*
-+ * Set device capabilities.
-+ */
-+ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
-+ __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags);
-+ if (!rt2x00_is_usb(rt2x00dev))
-+ __set_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags);
-+
-+ /*
-+ * Set device requirements.
-+ */
-+ if (!rt2x00_is_soc(rt2x00dev))
-+ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
-+ __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags);
-+ __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
-+ if (!rt2800_hwcrypt_disabled(rt2x00dev))
-+ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
-+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
-+ __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
-+ if (rt2x00_is_usb(rt2x00dev))
-+ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
-+ else {
-+ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
-+ __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
-+ }
-+
-+ /*
-+ * Set the rssi offset.
-+ */
-+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_probe_hw);
-+
-+/*
-+ * IEEE80211 stack callback functions.
-+ */
-+void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
-+ u16 *iv16)
-+{
-+ struct rt2x00_dev *rt2x00dev = hw->priv;
-+ struct mac_iveiv_entry iveiv_entry;
-+ u32 offset;
-+
-+ offset = MAC_IVEIV_ENTRY(hw_key_idx);
-+ rt2800_register_multiread(rt2x00dev, offset,
-+ &iveiv_entry, sizeof(iveiv_entry));
-+
-+ memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
-+ memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
-+}
-+EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
-+
-+int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
-+{
-+ struct rt2x00_dev *rt2x00dev = hw->priv;
-+ u32 reg;
-+ bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD);
-+
-+ rt2800_register_read(rt2x00dev, TX_RTS_CFG, &reg);
-+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES, value);
-+ rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, enabled);
-+ rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, enabled);
-+ rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, enabled);
-+ rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, enabled);
-+ rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, enabled);
-+ rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
-+ rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, enabled);
-+ rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
-+
-+int rt2800_conf_tx(struct ieee80211_hw *hw,
-+ struct ieee80211_vif *vif, u16 queue_idx,
-+ const struct ieee80211_tx_queue_params *params)
-+{
-+ struct rt2x00_dev *rt2x00dev = hw->priv;
-+ struct data_queue *queue;
-+ struct rt2x00_field32 field;
-+ int retval;
-+ u32 reg;
-+ u32 offset;
-+
-+ /*
-+ * First pass the configuration through rt2x00lib, that will
-+ * update the queue settings and validate the input. After that
-+ * we are free to update the registers based on the value
-+ * in the queue parameter.
-+ */
-+ retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
-+ if (retval)
-+ return retval;
-+
-+ /*
-+ * We only need to perform additional register initialization
-+ * for WMM queues/
-+ */
-+ if (queue_idx >= 4)
-+ return 0;
-+
-+ queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
-+
-+ /* Update WMM TXOP register */
-+ offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2)));
-+ field.bit_offset = (queue_idx & 1) * 16;
-+ field.bit_mask = 0xffff << field.bit_offset;
-+
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+ rt2x00_set_field32(&reg, field, queue->txop);
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+
-+ /* Update WMM registers */
-+ field.bit_offset = queue_idx * 4;
-+ field.bit_mask = 0xf << field.bit_offset;
-+
-+ rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, &reg);
-+ rt2x00_set_field32(&reg, field, queue->aifs);
-+ rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, &reg);
-+ rt2x00_set_field32(&reg, field, queue->cw_min);
-+ rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg);
-+
-+ rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, &reg);
-+ rt2x00_set_field32(&reg, field, queue->cw_max);
-+ rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg);
-+
-+ /* Update EDCA registers */
-+ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx);
-+
-+ rt2800_register_read(rt2x00dev, offset, &reg);
-+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_TX_OP, queue->txop);
-+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_AIFSN, queue->aifs);
-+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMIN, queue->cw_min);
-+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMAX, queue->cw_max);
-+ rt2800_register_write(rt2x00dev, offset, reg);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_conf_tx);
-+
-+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-+{
-+ struct rt2x00_dev *rt2x00dev = hw->priv;
-+ u64 tsf;
-+ u32 reg;
-+
-+ rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, &reg);
-+ tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32;
-+ rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, &reg);
-+ tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD);
-+
-+ return tsf;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_get_tsf);
-+
-+int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-+ enum ieee80211_ampdu_mlme_action action,
-+ struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-+ u8 buf_size)
-+{
-+ struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
-+ int ret = 0;
-+
-+ /*
-+ * Don't allow aggregation for stations the hardware isn't aware
-+ * of because tx status reports for frames to an unknown station
-+ * always contain wcid=255 and thus we can't distinguish between
-+ * multiple stations which leads to unwanted situations when the
-+ * hw reorders frames due to aggregation.
-+ */
-+ if (sta_priv->wcid < 0)
-+ return 1;
-+
-+ switch (action) {
-+ case IEEE80211_AMPDU_RX_START:
-+ case IEEE80211_AMPDU_RX_STOP:
-+ /*
-+ * The hw itself takes care of setting up BlockAck mechanisms.
-+ * So, we only have to allow mac80211 to nagotiate a BlockAck
-+ * agreement. Once that is done, the hw will BlockAck incoming
-+ * AMPDUs without further setup.
-+ */
-+ break;
-+ case IEEE80211_AMPDU_TX_START:
-+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-+ break;
-+ case IEEE80211_AMPDU_TX_STOP_CONT:
-+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
-+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
-+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-+ break;
-+ case IEEE80211_AMPDU_TX_OPERATIONAL:
-+ break;
-+ default:
-+ rt2x00_warn((struct rt2x00_dev *)hw->priv,
-+ "Unknown AMPDU action\n");
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
-+
-+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
-+ struct survey_info *survey)
-+{
-+ struct rt2x00_dev *rt2x00dev = hw->priv;
-+ struct ieee80211_conf *conf = &hw->conf;
-+ u32 idle, busy, busy_ext;
-+
-+ if (idx != 0)
-+ return -ENOENT;
-+
-+ survey->channel = conf->chandef.chan;
-+
-+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle);
-+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy);
-+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
-+
-+ if (idle || busy) {
-+ survey->filled = SURVEY_INFO_CHANNEL_TIME |
-+ SURVEY_INFO_CHANNEL_TIME_BUSY |
-+ SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
-+
-+ survey->channel_time = (idle + busy) / 1000;
-+ survey->channel_time_busy = busy / 1000;
-+ survey->channel_time_ext_busy = busy_ext / 1000;
-+ }
-+
-+ if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
-+ survey->filled |= SURVEY_INFO_IN_USE;
-+
-+ return 0;
-+
-+}
-+EXPORT_SYMBOL_GPL(rt2800_get_survey);
-+
-+MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
-+MODULE_VERSION(DRV_VERSION);
-+MODULE_DESCRIPTION("Ralink RT2800 library");
-+MODULE_LICENSE("GPL");
-diff -Nur linux-3.11.10.orig/drivers/spi/Kconfig linux-3.11.10/drivers/spi/Kconfig
---- linux-3.11.10.orig/drivers/spi/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/spi/Kconfig 2014-02-07 19:57:29.000000000 +0100
-@@ -86,6 +86,14 @@
- is for the regular SPI controller. Slave mode operation is not also
- not supported.
-
-+config SPI_BCM2708
-+ tristate "BCM2708 SPI controller driver (SPI0)"
-+ depends on MACH_BCM2708
-+ help
-+ This selects a driver for the Broadcom BCM2708 SPI master (SPI0). This
-+ driver is not compatible with the "Universal SPI Master" or the SPI slave
-+ device.
-+
- config SPI_BFIN5XX
- tristate "SPI controller driver for ADI Blackfin5xx"
- depends on BLACKFIN
-diff -Nur linux-3.11.10.orig/drivers/spi/Makefile linux-3.11.10/drivers/spi/Makefile
---- linux-3.11.10.orig/drivers/spi/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/spi/Makefile 2014-02-07 19:57:29.000000000 +0100
-@@ -17,6 +17,7 @@
- obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
- obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
- obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
-+obj-$(CONFIG_SPI_BCM2708) += spi-bcm2708.o
- obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
- obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
- obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
-diff -Nur linux-3.11.10.orig/drivers/spi/spi-bcm2708.c linux-3.11.10/drivers/spi/spi-bcm2708.c
---- linux-3.11.10.orig/drivers/spi/spi-bcm2708.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/spi/spi-bcm2708.c 2014-02-07 19:57:29.000000000 +0100
-@@ -0,0 +1,626 @@
-+/*
-+ * Driver for Broadcom BCM2708 SPI Controllers
-+ *
-+ * Copyright (C) 2012 Chris Boot
-+ *
-+ * This driver is inspired by:
-+ * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
-+ * spi-atmel.c, Copyright (C) 2006 Atmel Corporation
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/spinlock.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/platform_device.h>
-+#include <linux/io.h>
-+#include <linux/spi/spi.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include <linux/log2.h>
-+#include <linux/sched.h>
-+#include <linux/wait.h>
-+
-+/* SPI register offsets */
-+#define SPI_CS 0x00
-+#define SPI_FIFO 0x04
-+#define SPI_CLK 0x08
-+#define SPI_DLEN 0x0c
-+#define SPI_LTOH 0x10
-+#define SPI_DC 0x14
-+
-+/* Bitfields in CS */
-+#define SPI_CS_LEN_LONG 0x02000000
-+#define SPI_CS_DMA_LEN 0x01000000
-+#define SPI_CS_CSPOL2 0x00800000
-+#define SPI_CS_CSPOL1 0x00400000
-+#define SPI_CS_CSPOL0 0x00200000
-+#define SPI_CS_RXF 0x00100000
-+#define SPI_CS_RXR 0x00080000
-+#define SPI_CS_TXD 0x00040000
-+#define SPI_CS_RXD 0x00020000
-+#define SPI_CS_DONE 0x00010000
-+#define SPI_CS_LEN 0x00002000
-+#define SPI_CS_REN 0x00001000
-+#define SPI_CS_ADCS 0x00000800
-+#define SPI_CS_INTR 0x00000400
-+#define SPI_CS_INTD 0x00000200
-+#define SPI_CS_DMAEN 0x00000100
-+#define SPI_CS_TA 0x00000080
-+#define SPI_CS_CSPOL 0x00000040
-+#define SPI_CS_CLEAR_RX 0x00000020
-+#define SPI_CS_CLEAR_TX 0x00000010
-+#define SPI_CS_CPOL 0x00000008
-+#define SPI_CS_CPHA 0x00000004
-+#define SPI_CS_CS_10 0x00000002
-+#define SPI_CS_CS_01 0x00000001
-+
-+#define SPI_TIMEOUT_MS 150
-+
-+#define DRV_NAME "bcm2708_spi"
-+
-+struct bcm2708_spi {
-+ spinlock_t lock;
-+ void __iomem *base;
-+ int irq;
-+ struct clk *clk;
-+ bool stopping;
-+
-+ struct list_head queue;
-+ struct workqueue_struct *workq;
-+ struct work_struct work;
-+ struct completion done;
-+
-+ const u8 *tx_buf;
-+ u8 *rx_buf;
-+ int len;
-+};
-+
-+struct bcm2708_spi_state {
-+ u32 cs;
-+ u16 cdiv;
-+};
-+
-+/*
-+ * This function sets the ALT mode on the SPI pins so that we can use them with
-+ * the SPI hardware.
-+ *
-+ * FIXME: This is a hack. Use pinmux / pinctrl.
-+ */
-+static void bcm2708_init_pinmode(void)
-+{
-+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
-+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
-+
-+ int pin;
-+ u32 *gpio = ioremap(0x20200000, SZ_16K);
-+
-+ /* SPI is on GPIO 7..11 */
-+ for (pin = 7; pin <= 11; pin++) {
-+ INP_GPIO(pin); /* set mode to GPIO input first */
-+ SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
-+ }
-+
-+ iounmap(gpio);
-+
-+#undef INP_GPIO
-+#undef SET_GPIO_ALT
-+}
-+
-+static inline u32 bcm2708_rd(struct bcm2708_spi *bs, unsigned reg)
-+{
-+ return readl(bs->base + reg);
-+}
-+
-+static inline void bcm2708_wr(struct bcm2708_spi *bs, unsigned reg, u32 val)
-+{
-+ writel(val, bs->base + reg);
-+}
-+
-+static inline void bcm2708_rd_fifo(struct bcm2708_spi *bs, int len)
-+{
-+ u8 byte;
-+
-+ while (len--) {
-+ byte = bcm2708_rd(bs, SPI_FIFO);
-+ if (bs->rx_buf)
-+ *bs->rx_buf++ = byte;
-+ }
-+}
-+
-+static inline void bcm2708_wr_fifo(struct bcm2708_spi *bs, int len)
-+{
-+ u8 byte;
-+ u16 val;
-+
-+ if (len > bs->len)
-+ len = bs->len;
-+
-+ if (unlikely(bcm2708_rd(bs, SPI_CS) & SPI_CS_LEN)) {
-+ /* LoSSI mode */
-+ if (unlikely(len % 2)) {
-+ printk(KERN_ERR"bcm2708_wr_fifo: length must be even, skipping.\n");
-+ bs->len = 0;
-+ return;
-+ }
-+ while (len) {
-+ if (bs->tx_buf) {
-+ val = *(const u16 *)bs->tx_buf;
-+ bs->tx_buf += 2;
-+ } else
-+ val = 0;
-+ bcm2708_wr(bs, SPI_FIFO, val);
-+ bs->len -= 2;
-+ len -= 2;
-+ }
-+ return;
-+ }
-+
-+ while (len--) {
-+ byte = bs->tx_buf ? *bs->tx_buf++ : 0;
-+ bcm2708_wr(bs, SPI_FIFO, byte);
-+ bs->len--;
-+ }
-+}
-+
-+static irqreturn_t bcm2708_spi_interrupt(int irq, void *dev_id)
-+{
-+ struct spi_master *master = dev_id;
-+ struct bcm2708_spi *bs = spi_master_get_devdata(master);
-+ u32 cs;
-+
-+ spin_lock(&bs->lock);
-+
-+ cs = bcm2708_rd(bs, SPI_CS);
-+
-+ if (cs & SPI_CS_DONE) {
-+ if (bs->len) { /* first interrupt in a transfer */
-+ /* fill the TX fifo with up to 16 bytes */
-+ bcm2708_wr_fifo(bs, 16);
-+ } else { /* transfer complete */
-+ /* disable interrupts */
-+ cs &= ~(SPI_CS_INTR | SPI_CS_INTD);
-+ bcm2708_wr(bs, SPI_CS, cs);
-+
-+ /* drain RX FIFO */
-+ while (cs & SPI_CS_RXD) {
-+ bcm2708_rd_fifo(bs, 1);
-+ cs = bcm2708_rd(bs, SPI_CS);
-+ }
-+
-+ /* wake up our bh */
-+ complete(&bs->done);
-+ }
-+ } else if (cs & SPI_CS_RXR) {
-+ /* read 12 bytes of data */
-+ bcm2708_rd_fifo(bs, 12);
-+
-+ /* write up to 12 bytes */
-+ bcm2708_wr_fifo(bs, 12);
-+ }
-+
-+ spin_unlock(&bs->lock);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int bcm2708_setup_state(struct spi_master *master,
-+ struct device *dev, struct bcm2708_spi_state *state,
-+ u32 hz, u8 csel, u8 mode, u8 bpw)
-+{
-+ struct bcm2708_spi *bs = spi_master_get_devdata(master);
-+ int cdiv;
-+ unsigned long bus_hz;
-+ u32 cs = 0;
-+
-+ bus_hz = clk_get_rate(bs->clk);
-+
-+ if (hz >= bus_hz) {
-+ cdiv = 2; /* bus_hz / 2 is as fast as we can go */
-+ } else if (hz) {
-+ cdiv = DIV_ROUND_UP(bus_hz, hz);
-+
-+ /* CDIV must be a power of 2, so round up */
-+ cdiv = roundup_pow_of_two(cdiv);
-+
-+ if (cdiv > 65536) {
-+ dev_dbg(dev,
-+ "setup: %d Hz too slow, cdiv %u; min %ld Hz\n",
-+ hz, cdiv, bus_hz / 65536);
-+ return -EINVAL;
-+ } else if (cdiv == 65536) {
-+ cdiv = 0;
-+ } else if (cdiv == 1) {
-+ cdiv = 2; /* 1 gets rounded down to 0; == 65536 */
-+ }
-+ } else {
-+ cdiv = 0;
-+ }
-+
-+ switch (bpw) {
-+ case 8:
-+ break;
-+ case 9:
-+ /* Reading in LoSSI mode is a special case. See 'BCM2835 ARM Peripherals' datasheet */
-+ cs |= SPI_CS_LEN;
-+ break;
-+ default:
-+ dev_dbg(dev, "setup: invalid bits_per_word %u (must be 8 or 9)\n",
-+ bpw);
-+ return -EINVAL;
-+ }
-+
-+ if (mode & SPI_CPOL)
-+ cs |= SPI_CS_CPOL;
-+ if (mode & SPI_CPHA)
-+ cs |= SPI_CS_CPHA;
-+
-+ if (!(mode & SPI_NO_CS)) {
-+ if (mode & SPI_CS_HIGH) {
-+ cs |= SPI_CS_CSPOL;
-+ cs |= SPI_CS_CSPOL0 << csel;
-+ }
-+
-+ cs |= csel;
-+ } else {
-+ cs |= SPI_CS_CS_10 | SPI_CS_CS_01;
-+ }
-+
-+ if (state) {
-+ state->cs = cs;
-+ state->cdiv = cdiv;
-+ dev_dbg(dev, "setup: want %d Hz; "
-+ "bus_hz=%lu / cdiv=%u == %lu Hz; "
-+ "mode %u: cs 0x%08X\n",
-+ hz, bus_hz, cdiv, bus_hz/cdiv, mode, cs);
-+ }
-+
-+ return 0;
-+}
-+
-+static int bcm2708_process_transfer(struct bcm2708_spi *bs,
-+ struct spi_message *msg, struct spi_transfer *xfer)
-+{
-+ struct spi_device *spi = msg->spi;
-+ struct bcm2708_spi_state state, *stp;
-+ int ret;
-+ u32 cs;
-+
-+ if (bs->stopping)
-+ return -ESHUTDOWN;
-+
-+ if (xfer->bits_per_word || xfer->speed_hz) {
-+ ret = bcm2708_setup_state(spi->master, &spi->dev, &state,
-+ xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
-+ spi->chip_select, spi->mode,
-+ xfer->bits_per_word ? xfer->bits_per_word :
-+ spi->bits_per_word);
-+ if (ret)
-+ return ret;
-+
-+ stp = &state;
-+ } else {
-+ stp = spi->controller_state;
-+ }
-+
-+ INIT_COMPLETION(bs->done);
-+ bs->tx_buf = xfer->tx_buf;
-+ bs->rx_buf = xfer->rx_buf;
-+ bs->len = xfer->len;
-+
-+ cs = stp->cs | SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA;
-+
-+ bcm2708_wr(bs, SPI_CLK, stp->cdiv);
-+ bcm2708_wr(bs, SPI_CS, cs);
-+
-+ ret = wait_for_completion_timeout(&bs->done,
-+ msecs_to_jiffies(SPI_TIMEOUT_MS));
-+ if (ret == 0) {
-+ dev_err(&spi->dev, "transfer timed out\n");
-+ return -ETIMEDOUT;
-+ }
-+
-+ if (xfer->delay_usecs)
-+ udelay(xfer->delay_usecs);
-+
-+ if (list_is_last(&xfer->transfer_list, &msg->transfers) ||
-+ xfer->cs_change) {
-+ /* clear TA and interrupt flags */
-+ bcm2708_wr(bs, SPI_CS, stp->cs);
-+ }
-+
-+ msg->actual_length += (xfer->len - bs->len);
-+
-+ return 0;
-+}
-+
-+static void bcm2708_work(struct work_struct *work)
-+{
-+ struct bcm2708_spi *bs = container_of(work, struct bcm2708_spi, work);
-+ unsigned long flags;
-+ struct spi_message *msg;
-+ struct spi_transfer *xfer;
-+ int status = 0;
-+
-+ spin_lock_irqsave(&bs->lock, flags);
-+ while (!list_empty(&bs->queue)) {
-+ msg = list_first_entry(&bs->queue, struct spi_message, queue);
-+ list_del_init(&msg->queue);
-+ spin_unlock_irqrestore(&bs->lock, flags);
-+
-+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-+ status = bcm2708_process_transfer(bs, msg, xfer);
-+ if (status)
-+ break;
-+ }
-+
-+ msg->status = status;
-+ msg->complete(msg->context);
-+
-+ spin_lock_irqsave(&bs->lock, flags);
-+ }
-+ spin_unlock_irqrestore(&bs->lock, flags);
-+}
-+
-+static int bcm2708_spi_setup(struct spi_device *spi)
-+{
-+ struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
-+ struct bcm2708_spi_state *state;
-+ int ret;
-+
-+ if (bs->stopping)
-+ return -ESHUTDOWN;
-+
-+ if (!(spi->mode & SPI_NO_CS) &&
-+ (spi->chip_select > spi->master->num_chipselect)) {
-+ dev_dbg(&spi->dev,
-+ "setup: invalid chipselect %u (%u defined)\n",
-+ spi->chip_select, spi->master->num_chipselect);
-+ return -EINVAL;
-+ }
-+
-+ state = spi->controller_state;
-+ if (!state) {
-+ state = kzalloc(sizeof(*state), GFP_KERNEL);
-+ if (!state)
-+ return -ENOMEM;
-+
-+ spi->controller_state = state;
-+ }
-+
-+ ret = bcm2708_setup_state(spi->master, &spi->dev, state,
-+ spi->max_speed_hz, spi->chip_select, spi->mode,
-+ spi->bits_per_word);
-+ if (ret < 0) {
-+ kfree(state);
-+ spi->controller_state = NULL;
-+ return ret;
-+ }
-+
-+ dev_dbg(&spi->dev,
-+ "setup: cd %d: %d Hz, bpw %u, mode 0x%x -> CS=%08x CDIV=%04x\n",
-+ spi->chip_select, spi->max_speed_hz, spi->bits_per_word,
-+ spi->mode, state->cs, state->cdiv);
-+
-+ return 0;
-+}
-+
-+static int bcm2708_spi_transfer(struct spi_device *spi, struct spi_message *msg)
-+{
-+ struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
-+ struct spi_transfer *xfer;
-+ int ret;
-+ unsigned long flags;
-+
-+ if (unlikely(list_empty(&msg->transfers)))
-+ return -EINVAL;
-+
-+ if (bs->stopping)
-+ return -ESHUTDOWN;
-+
-+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-+ if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
-+ dev_dbg(&spi->dev, "missing rx or tx buf\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!xfer->bits_per_word || xfer->speed_hz)
-+ continue;
-+
-+ ret = bcm2708_setup_state(spi->master, &spi->dev, NULL,
-+ xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
-+ spi->chip_select, spi->mode,
-+ xfer->bits_per_word ? xfer->bits_per_word :
-+ spi->bits_per_word);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ msg->status = -EINPROGRESS;
-+ msg->actual_length = 0;
-+
-+ spin_lock_irqsave(&bs->lock, flags);
-+ list_add_tail(&msg->queue, &bs->queue);
-+ queue_work(bs->workq, &bs->work);
-+ spin_unlock_irqrestore(&bs->lock, flags);
-+
-+ return 0;
-+}
-+
-+static void bcm2708_spi_cleanup(struct spi_device *spi)
-+{
-+ if (spi->controller_state) {
-+ kfree(spi->controller_state);
-+ spi->controller_state = NULL;
-+ }
-+}
-+
-+static int bcm2708_spi_probe(struct platform_device *pdev)
-+{
-+ struct resource *regs;
-+ int irq, err = -ENOMEM;
-+ struct clk *clk;
-+ struct spi_master *master;
-+ struct bcm2708_spi *bs;
-+
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!regs) {
-+ dev_err(&pdev->dev, "could not get IO memory\n");
-+ return -ENXIO;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0) {
-+ dev_err(&pdev->dev, "could not get IRQ\n");
-+ return irq;
-+ }
-+
-+ clk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(clk)) {
-+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
-+ return PTR_ERR(clk);
-+ }
-+
-+ bcm2708_init_pinmode();
-+
-+ master = spi_alloc_master(&pdev->dev, sizeof(*bs));
-+ if (!master) {
-+ dev_err(&pdev->dev, "spi_alloc_master() failed\n");
-+ goto out_clk_put;
-+ }
-+
-+ /* the spi->mode bits understood by this driver: */
-+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
-+
-+ master->bus_num = pdev->id;
-+ master->num_chipselect = 3;
-+ master->setup = bcm2708_spi_setup;
-+ master->transfer = bcm2708_spi_transfer;
-+ master->cleanup = bcm2708_spi_cleanup;
-+ platform_set_drvdata(pdev, master);
-+
-+ bs = spi_master_get_devdata(master);
-+
-+ spin_lock_init(&bs->lock);
-+ INIT_LIST_HEAD(&bs->queue);
-+ init_completion(&bs->done);
-+ INIT_WORK(&bs->work, bcm2708_work);
-+
-+ bs->base = ioremap(regs->start, resource_size(regs));
-+ if (!bs->base) {
-+ dev_err(&pdev->dev, "could not remap memory\n");
-+ goto out_master_put;
-+ }
-+
-+ bs->workq = create_singlethread_workqueue(dev_name(&pdev->dev));
-+ if (!bs->workq) {
-+ dev_err(&pdev->dev, "could not create workqueue\n");
-+ goto out_iounmap;
-+ }
-+
-+ bs->irq = irq;
-+ bs->clk = clk;
-+ bs->stopping = false;
-+
-+ err = request_irq(irq, bcm2708_spi_interrupt, 0, dev_name(&pdev->dev),
-+ master);
-+ if (err) {
-+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
-+ goto out_workqueue;
-+ }
-+
-+ /* initialise the hardware */
-+ clk_enable(clk);
-+ bcm2708_wr(bs, SPI_CS, SPI_CS_REN | SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
-+
-+ err = spi_register_master(master);
-+ if (err) {
-+ dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
-+ goto out_free_irq;
-+ }
-+
-+ dev_info(&pdev->dev, "SPI Controller at 0x%08lx (irq %d)\n",
-+ (unsigned long)regs->start, irq);
-+
-+ return 0;
-+
-+out_free_irq:
-+ free_irq(bs->irq, master);
-+out_workqueue:
-+ destroy_workqueue(bs->workq);
-+out_iounmap:
-+ iounmap(bs->base);
-+out_master_put:
-+ spi_master_put(master);
-+out_clk_put:
-+ clk_put(clk);
-+ return err;
-+}
-+
-+static int bcm2708_spi_remove(struct platform_device *pdev)
-+{
-+ struct spi_master *master = platform_get_drvdata(pdev);
-+ struct bcm2708_spi *bs = spi_master_get_devdata(master);
-+
-+ /* reset the hardware and block queue progress */
-+ spin_lock_irq(&bs->lock);
-+ bs->stopping = true;
-+ bcm2708_wr(bs, SPI_CS, SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
-+ spin_unlock_irq(&bs->lock);
-+
-+ flush_work_sync(&bs->work);
-+
-+ clk_disable(bs->clk);
-+ clk_put(bs->clk);
-+ free_irq(bs->irq, master);
-+ iounmap(bs->base);
-+
-+ spi_unregister_master(master);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm2708_spi_driver = {
-+ .driver = {
-+ .name = DRV_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = bcm2708_spi_probe,
-+ .remove = bcm2708_spi_remove,
-+};
-+
-+
-+static int __init bcm2708_spi_init(void)
-+{
-+ return platform_driver_probe(&bcm2708_spi_driver, bcm2708_spi_probe);
-+}
-+module_init(bcm2708_spi_init);
-+
-+static void __exit bcm2708_spi_exit(void)
-+{
-+ platform_driver_unregister(&bcm2708_spi_driver);
-+}
-+module_exit(bcm2708_spi_exit);
-+
-+
-+//module_platform_driver(bcm2708_spi_driver);
-+
-+MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2708");
-+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:" DRV_NAME);
-diff -Nur linux-3.11.10.orig/drivers/staging/media/lirc/Kconfig linux-3.11.10/drivers/staging/media/lirc/Kconfig
---- linux-3.11.10.orig/drivers/staging/media/lirc/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/staging/media/lirc/Kconfig 2014-02-07 19:57:29.000000000 +0100
-@@ -38,6 +38,12 @@
- help
- Driver for Homebrew Parallel Port Receivers
-
-+config LIRC_RPI
-+ tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi"
-+ depends on LIRC
-+ help
-+ Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi
-+
- config LIRC_SASEM
- tristate "Sasem USB IR Remote"
- depends on LIRC && USB
-diff -Nur linux-3.11.10.orig/drivers/staging/media/lirc/lirc_rpi.c linux-3.11.10/drivers/staging/media/lirc/lirc_rpi.c
---- linux-3.11.10.orig/drivers/staging/media/lirc/lirc_rpi.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/staging/media/lirc/lirc_rpi.c 2014-02-07 19:57:29.000000000 +0100
-@@ -0,0 +1,692 @@
-+/*
-+ * lirc_rpi.c
-+ *
-+ * lirc_rpi - Device driver that records pulse- and pause-lengths
-+ * (space-lengths) (just like the lirc_serial driver does)
-+ * between GPIO interrupt events on the Raspberry Pi.
-+ * Lots of code has been taken from the lirc_serial module,
-+ * so I would like say thanks to the authors.
-+ *
-+ * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>,
-+ * Michael Bishop <cleverca22@gmail.com>
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/kernel.h>
-+#include <linux/time.h>
-+#include <linux/string.h>
-+#include <linux/delay.h>
-+#include <linux/platform_device.h>
-+#include <linux/irq.h>
-+#include <linux/spinlock.h>
-+#include <media/lirc.h>
-+#include <media/lirc_dev.h>
-+#include <linux/gpio.h>
-+
-+#define LIRC_DRIVER_NAME "lirc_rpi"
-+#define RBUF_LEN 256
-+#define LIRC_TRANSMITTER_LATENCY 256
-+
-+#ifndef MAX_UDELAY_MS
-+#define MAX_UDELAY_US 5000
-+#else
-+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
-+#endif
-+
-+#define dprintk(fmt, args...) \
-+ do { \
-+ if (debug) \
-+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
-+ fmt, ## args); \
-+ } while (0)
-+
-+/* module parameters */
-+
-+/* set the default GPIO input pin */
-+static int gpio_in_pin = 18;
-+/* set the default GPIO output pin */
-+static int gpio_out_pin = 17;
-+/* enable debugging messages */
-+static int debug;
-+/* -1 = auto, 0 = active high, 1 = active low */
-+static int sense = -1;
-+/* use softcarrier by default */
-+static int softcarrier = 1;
-+/* 0 = do not invert output, 1 = invert output */
-+static int invert = 0;
-+
-+struct gpio_chip *gpiochip;
-+struct irq_chip *irqchip;
-+struct irq_data *irqdata;
-+
-+/* forward declarations */
-+static long send_pulse(unsigned long length);
-+static void send_space(long length);
-+static void lirc_rpi_exit(void);
-+
-+int valid_gpio_pins[] = { 0, 1, 4, 8, 7, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23,
-+ 24, 25 };
-+
-+static struct platform_device *lirc_rpi_dev;
-+static struct timeval lasttv = { 0, 0 };
-+static struct lirc_buffer rbuf;
-+static spinlock_t lock;
-+
-+/* initialized/set in init_timing_params() */
-+static unsigned int freq = 38000;
-+static unsigned int duty_cycle = 50;
-+static unsigned long period;
-+static unsigned long pulse_width;
-+static unsigned long space_width;
-+
-+static void safe_udelay(unsigned long usecs)
-+{
-+ while (usecs > MAX_UDELAY_US) {
-+ udelay(MAX_UDELAY_US);
-+ usecs -= MAX_UDELAY_US;
-+ }
-+ udelay(usecs);
-+}
-+
-+static int init_timing_params(unsigned int new_duty_cycle,
-+ unsigned int new_freq)
-+{
-+ /*
-+ * period, pulse/space width are kept with 8 binary places -
-+ * IE multiplied by 256.
-+ */
-+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
-+ LIRC_TRANSMITTER_LATENCY)
-+ return -EINVAL;
-+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
-+ LIRC_TRANSMITTER_LATENCY)
-+ return -EINVAL;
-+ duty_cycle = new_duty_cycle;
-+ freq = new_freq;
-+ period = 256 * 1000000L / freq;
-+ pulse_width = period * duty_cycle / 100;
-+ space_width = period - pulse_width;
-+ dprintk("in init_timing_params, freq=%d pulse=%ld, "
-+ "space=%ld\n", freq, pulse_width, space_width);
-+ return 0;
-+}
-+
-+static long send_pulse_softcarrier(unsigned long length)
-+{
-+ int flag;
-+ unsigned long actual, target, d;
-+
-+ length <<= 8;
-+
-+ actual = 0; target = 0; flag = 0;
-+ while (actual < length) {
-+ if (flag) {
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+ target += space_width;
-+ } else {
-+ gpiochip->set(gpiochip, gpio_out_pin, !invert);
-+ target += pulse_width;
-+ }
-+ d = (target - actual -
-+ LIRC_TRANSMITTER_LATENCY + 128) >> 8;
-+ /*
-+ * Note - we've checked in ioctl that the pulse/space
-+ * widths are big enough so that d is > 0
-+ */
-+ udelay(d);
-+ actual += (d << 8) + LIRC_TRANSMITTER_LATENCY;
-+ flag = !flag;
-+ }
-+ return (actual-length) >> 8;
-+}
-+
-+static long send_pulse(unsigned long length)
-+{
-+ if (length <= 0)
-+ return 0;
-+
-+ if (softcarrier) {
-+ return send_pulse_softcarrier(length);
-+ } else {
-+ gpiochip->set(gpiochip, gpio_out_pin, !invert);
-+ safe_udelay(length);
-+ return 0;
-+ }
-+}
-+
-+static void send_space(long length)
-+{
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+ if (length <= 0)
-+ return;
-+ safe_udelay(length);
-+}
-+
-+static void rbwrite(int l)
-+{
-+ if (lirc_buffer_full(&rbuf)) {
-+ /* no new signals will be accepted */
-+ dprintk("Buffer overrun\n");
-+ return;
-+ }
-+ lirc_buffer_write(&rbuf, (void *)&l);
-+}
-+
-+static void frbwrite(int l)
-+{
-+ /* simple noise filter */
-+ static int pulse, space;
-+ static unsigned int ptr;
-+
-+ if (ptr > 0 && (l & PULSE_BIT)) {
-+ pulse += l & PULSE_MASK;
-+ if (pulse > 250) {
-+ rbwrite(space);
-+ rbwrite(pulse | PULSE_BIT);
-+ ptr = 0;
-+ pulse = 0;
-+ }
-+ return;
-+ }
-+ if (!(l & PULSE_BIT)) {
-+ if (ptr == 0) {
-+ if (l > 20000) {
-+ space = l;
-+ ptr++;
-+ return;
-+ }
-+ } else {
-+ if (l > 20000) {
-+ space += pulse;
-+ if (space > PULSE_MASK)
-+ space = PULSE_MASK;
-+ space += l;
-+ if (space > PULSE_MASK)
-+ space = PULSE_MASK;
-+ pulse = 0;
-+ return;
-+ }
-+ rbwrite(space);
-+ rbwrite(pulse | PULSE_BIT);
-+ ptr = 0;
-+ pulse = 0;
-+ }
-+ }
-+ rbwrite(l);
-+}
-+
-+static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs)
-+{
-+ struct timeval tv;
-+ long deltv;
-+ int data;
-+ int signal;
-+
-+ /* use the GPIO signal level */
-+ signal = gpiochip->get(gpiochip, gpio_in_pin);
-+
-+ /* unmask the irq */
-+ irqchip->irq_unmask(irqdata);
-+
-+ if (sense != -1) {
-+ /* get current time */
-+ do_gettimeofday(&tv);
-+
-+ /* calc time since last interrupt in microseconds */
-+ deltv = tv.tv_sec-lasttv.tv_sec;
-+ if (tv.tv_sec < lasttv.tv_sec ||
-+ (tv.tv_sec == lasttv.tv_sec &&
-+ tv.tv_usec < lasttv.tv_usec)) {
-+ printk(KERN_WARNING LIRC_DRIVER_NAME
-+ ": AIEEEE: your clock just jumped backwards\n");
-+ printk(KERN_WARNING LIRC_DRIVER_NAME
-+ ": %d %d %lx %lx %lx %lx\n", signal, sense,
-+ tv.tv_sec, lasttv.tv_sec,
-+ tv.tv_usec, lasttv.tv_usec);
-+ data = PULSE_MASK;
-+ } else if (deltv > 15) {
-+ data = PULSE_MASK; /* really long time */
-+ if (!(signal^sense)) {
-+ /* sanity check */
-+ printk(KERN_WARNING LIRC_DRIVER_NAME
-+ ": AIEEEE: %d %d %lx %lx %lx %lx\n",
-+ signal, sense, tv.tv_sec, lasttv.tv_sec,
-+ tv.tv_usec, lasttv.tv_usec);
-+ /*
-+ * detecting pulse while this
-+ * MUST be a space!
-+ */
-+ sense = sense ? 0 : 1;
-+ }
-+ } else {
-+ data = (int) (deltv*1000000 +
-+ (tv.tv_usec - lasttv.tv_usec));
-+ }
-+ frbwrite(signal^sense ? data : (data|PULSE_BIT));
-+ lasttv = tv;
-+ wake_up_interruptible(&rbuf.wait_poll);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int is_right_chip(struct gpio_chip *chip, void *data)
-+{
-+ dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label));
-+
-+ if (strcmp(data, chip->label) == 0)
-+ return 1;
-+ return 0;
-+}
-+
-+static int init_port(void)
-+{
-+ int i, nlow, nhigh, ret, irq;
-+
-+ gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
-+
-+ if (!gpiochip)
-+ return -ENODEV;
-+
-+ if (gpio_request(gpio_out_pin, LIRC_DRIVER_NAME " ir/out")) {
-+ printk(KERN_ALERT LIRC_DRIVER_NAME
-+ ": cant claim gpio pin %d\n", gpio_out_pin);
-+ ret = -ENODEV;
-+ goto exit_init_port;
-+ }
-+
-+ if (gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in")) {
-+ printk(KERN_ALERT LIRC_DRIVER_NAME
-+ ": cant claim gpio pin %d\n", gpio_in_pin);
-+ ret = -ENODEV;
-+ goto exit_gpio_free_out_pin;
-+ }
-+
-+ gpiochip->direction_input(gpiochip, gpio_in_pin);
-+ gpiochip->direction_output(gpiochip, gpio_out_pin, 1);
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+
-+ irq = gpiochip->to_irq(gpiochip, gpio_in_pin);
-+ dprintk("to_irq %d\n", irq);
-+ irqdata = irq_get_irq_data(irq);
-+
-+ if (irqdata && irqdata->chip) {
-+ irqchip = irqdata->chip;
-+ } else {
-+ ret = -ENODEV;
-+ goto exit_gpio_free_in_pin;
-+ }
-+
-+ /* if pin is high, then this must be an active low receiver. */
-+ if (sense == -1) {
-+ /* wait 1/2 sec for the power supply */
-+ msleep(500);
-+
-+ /*
-+ * probe 9 times every 0.04s, collect "votes" for
-+ * active high/low
-+ */
-+ nlow = 0;
-+ nhigh = 0;
-+ for (i = 0; i < 9; i++) {
-+ if (gpiochip->get(gpiochip, gpio_in_pin))
-+ nlow++;
-+ else
-+ nhigh++;
-+ msleep(40);
-+ }
-+ sense = (nlow >= nhigh ? 1 : 0);
-+ printk(KERN_INFO LIRC_DRIVER_NAME
-+ ": auto-detected active %s receiver on GPIO pin %d\n",
-+ sense ? "low" : "high", gpio_in_pin);
-+ } else {
-+ printk(KERN_INFO LIRC_DRIVER_NAME
-+ ": manually using active %s receiver on GPIO pin %d\n",
-+ sense ? "low" : "high", gpio_in_pin);
-+ }
-+
-+ return 0;
-+
-+ exit_gpio_free_in_pin:
-+ gpio_free(gpio_in_pin);
-+
-+ exit_gpio_free_out_pin:
-+ gpio_free(gpio_out_pin);
-+
-+ exit_init_port:
-+ return ret;
-+}
-+
-+// called when the character device is opened
-+static int set_use_inc(void *data)
-+{
-+ int result;
-+ unsigned long flags;
-+
-+ /* initialize timestamp */
-+ do_gettimeofday(&lasttv);
-+
-+ result = request_irq(gpiochip->to_irq(gpiochip, gpio_in_pin),
-+ (irq_handler_t) irq_handler, 0,
-+ LIRC_DRIVER_NAME, (void*) 0);
-+
-+ switch (result) {
-+ case -EBUSY:
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": IRQ %d is busy\n",
-+ gpiochip->to_irq(gpiochip, gpio_in_pin));
-+ return -EBUSY;
-+ case -EINVAL:
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": Bad irq number or handler\n");
-+ return -EINVAL;
-+ default:
-+ dprintk("Interrupt %d obtained\n",
-+ gpiochip->to_irq(gpiochip, gpio_in_pin));
-+ break;
-+ };
-+
-+ /* initialize pulse/space widths */
-+ init_timing_params(duty_cycle, freq);
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ /* GPIO Pin Falling/Rising Edge Detect Enable */
-+ irqchip->irq_set_type(irqdata,
-+ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING);
-+
-+ /* unmask the irq */
-+ irqchip->irq_unmask(irqdata);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+
-+ return 0;
-+}
-+
-+static void set_use_dec(void *data)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ /* GPIO Pin Falling/Rising Edge Detect Disable */
-+ irqchip->irq_set_type(irqdata, 0);
-+ irqchip->irq_mask(irqdata);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+
-+ free_irq(gpiochip->to_irq(gpiochip, gpio_in_pin), (void *) 0);
-+
-+ dprintk(KERN_INFO LIRC_DRIVER_NAME
-+ ": freed IRQ %d\n", gpiochip->to_irq(gpiochip, gpio_in_pin));
-+}
-+
-+static ssize_t lirc_write(struct file *file, const char *buf,
-+ size_t n, loff_t *ppos)
-+{
-+ int i, count;
-+ unsigned long flags;
-+ long delta = 0;
-+ int *wbuf;
-+
-+ count = n / sizeof(int);
-+ if (n % sizeof(int) || count % 2 == 0)
-+ return -EINVAL;
-+ wbuf = memdup_user(buf, n);
-+ if (IS_ERR(wbuf))
-+ return PTR_ERR(wbuf);
-+ spin_lock_irqsave(&lock, flags);
-+
-+ for (i = 0; i < count; i++) {
-+ if (i%2)
-+ send_space(wbuf[i] - delta);
-+ else
-+ delta = send_pulse(wbuf[i]);
-+ }
-+ gpiochip->set(gpiochip, gpio_out_pin, invert);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+ kfree(wbuf);
-+ return n;
-+}
-+
-+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-+{
-+ int result;
-+ __u32 value;
-+
-+ switch (cmd) {
-+ case LIRC_GET_SEND_MODE:
-+ return -ENOIOCTLCMD;
-+ break;
-+
-+ case LIRC_SET_SEND_MODE:
-+ result = get_user(value, (__u32 *) arg);
-+ if (result)
-+ return result;
-+ /* only LIRC_MODE_PULSE supported */
-+ if (value != LIRC_MODE_PULSE)
-+ return -ENOSYS;
-+ break;
-+
-+ case LIRC_GET_LENGTH:
-+ return -ENOSYS;
-+ break;
-+
-+ case LIRC_SET_SEND_DUTY_CYCLE:
-+ dprintk("SET_SEND_DUTY_CYCLE\n");
-+ result = get_user(value, (__u32 *) arg);
-+ if (result)
-+ return result;
-+ if (value <= 0 || value > 100)
-+ return -EINVAL;
-+ return init_timing_params(value, freq);
-+ break;
-+
-+ case LIRC_SET_SEND_CARRIER:
-+ dprintk("SET_SEND_CARRIER\n");
-+ result = get_user(value, (__u32 *) arg);
-+ if (result)
-+ return result;
-+ if (value > 500000 || value < 20000)
-+ return -EINVAL;
-+ return init_timing_params(duty_cycle, value);
-+ break;
-+
-+ default:
-+ return lirc_dev_fop_ioctl(filep, cmd, arg);
-+ }
-+ return 0;
-+}
-+
-+static const struct file_operations lirc_fops = {
-+ .owner = THIS_MODULE,
-+ .write = lirc_write,
-+ .unlocked_ioctl = lirc_ioctl,
-+ .read = lirc_dev_fop_read,
-+ .poll = lirc_dev_fop_poll,
-+ .open = lirc_dev_fop_open,
-+ .release = lirc_dev_fop_close,
-+ .llseek = no_llseek,
-+};
-+
-+static struct lirc_driver driver = {
-+ .name = LIRC_DRIVER_NAME,
-+ .minor = -1,
-+ .code_length = 1,
-+ .sample_rate = 0,
-+ .data = NULL,
-+ .add_to_buf = NULL,
-+ .rbuf = &rbuf,
-+ .set_use_inc = set_use_inc,
-+ .set_use_dec = set_use_dec,
-+ .fops = &lirc_fops,
-+ .dev = NULL,
-+ .owner = THIS_MODULE,
-+};
-+
-+static struct platform_driver lirc_rpi_driver = {
-+ .driver = {
-+ .name = LIRC_DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init lirc_rpi_init(void)
-+{
-+ int result;
-+
-+ /* Init read buffer. */
-+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
-+ if (result < 0)
-+ return -ENOMEM;
-+
-+ result = platform_driver_register(&lirc_rpi_driver);
-+ if (result) {
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": lirc register returned %d\n", result);
-+ goto exit_buffer_free;
-+ }
-+
-+ lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
-+ if (!lirc_rpi_dev) {
-+ result = -ENOMEM;
-+ goto exit_driver_unregister;
-+ }
-+
-+ result = platform_device_add(lirc_rpi_dev);
-+ if (result)
-+ goto exit_device_put;
-+
-+ return 0;
-+
-+ exit_device_put:
-+ platform_device_put(lirc_rpi_dev);
-+
-+ exit_driver_unregister:
-+ platform_driver_unregister(&lirc_rpi_driver);
-+
-+ exit_buffer_free:
-+ lirc_buffer_free(&rbuf);
-+
-+ return result;
-+}
-+
-+static void lirc_rpi_exit(void)
-+{
-+ gpio_free(gpio_out_pin);
-+ gpio_free(gpio_in_pin);
-+ platform_device_unregister(lirc_rpi_dev);
-+ platform_driver_unregister(&lirc_rpi_driver);
-+ lirc_buffer_free(&rbuf);
-+}
-+
-+static int __init lirc_rpi_init_module(void)
-+{
-+ int result, i;
-+
-+ result = lirc_rpi_init();
-+ if (result)
-+ return result;
-+
-+ /* check if the module received valid gpio pin numbers */
-+ result = 0;
-+ if (gpio_in_pin != gpio_out_pin) {
-+ for(i = 0; (i < ARRAY_SIZE(valid_gpio_pins)) && (result != 2); i++) {
-+ if (gpio_in_pin == valid_gpio_pins[i] ||
-+ gpio_out_pin == valid_gpio_pins[i]) {
-+ result++;
-+ }
-+ }
-+ }
-+
-+ if (result != 2) {
-+ result = -EINVAL;
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": invalid GPIO pin(s) specified!\n");
-+ goto exit_rpi;
-+ }
-+
-+ driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE |
-+ LIRC_CAN_SET_SEND_CARRIER |
-+ LIRC_CAN_SEND_PULSE |
-+ LIRC_CAN_REC_MODE2;
-+
-+ driver.dev = &lirc_rpi_dev->dev;
-+ driver.minor = lirc_register_driver(&driver);
-+
-+ if (driver.minor < 0) {
-+ printk(KERN_ERR LIRC_DRIVER_NAME
-+ ": device registration failed with %d\n", result);
-+ result = -EIO;
-+ goto exit_rpi;
-+ }
-+
-+ printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
-+
-+ result = init_port();
-+ if (result < 0)
-+ goto exit_rpi;
-+
-+ return 0;
-+
-+ exit_rpi:
-+ lirc_rpi_exit();
-+
-+ return result;
-+}
-+
-+static void __exit lirc_rpi_exit_module(void)
-+{
-+ lirc_rpi_exit();
-+
-+ lirc_unregister_driver(driver.minor);
-+ printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
-+}
-+
-+module_init(lirc_rpi_init_module);
-+module_exit(lirc_rpi_exit_module);
-+
-+MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO.");
-+MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>");
-+MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>");
-+MODULE_LICENSE("GPL");
-+
-+module_param(gpio_out_pin, int, S_IRUGO);
-+MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM"
-+ " processor. Valid pin numbers are: 0, 1, 4, 8, 7, 9, 10, 11,"
-+ " 14, 15, 17, 18, 21, 22, 23, 24, 25, default 17");
-+
-+module_param(gpio_in_pin, int, S_IRUGO);
-+MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor."
-+ " Valid pin numbers are: 0, 1, 4, 8, 7, 9, 10, 11, 14, 15,"
-+ " 17, 18, 21, 22, 23, 24, 25, default 18");
-+
-+module_param(sense, bool, S_IRUGO);
-+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
-+ " (0 = active high, 1 = active low )");
-+
-+module_param(softcarrier, bool, S_IRUGO);
-+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
-+
-+module_param(invert, bool, S_IRUGO);
-+MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off");
-+
-+module_param(debug, bool, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(debug, "Enable debugging messages");
-diff -Nur linux-3.11.10.orig/drivers/staging/media/lirc/Makefile linux-3.11.10/drivers/staging/media/lirc/Makefile
---- linux-3.11.10.orig/drivers/staging/media/lirc/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/staging/media/lirc/Makefile 2014-02-07 19:57:29.000000000 +0100
-@@ -7,6 +7,7 @@
- obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
- obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
- obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
-+obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o
- obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
- obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
- obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
-diff -Nur linux-3.11.10.orig/drivers/thermal/bcm2835-thermal.c linux-3.11.10/drivers/thermal/bcm2835-thermal.c
---- linux-3.11.10.orig/drivers/thermal/bcm2835-thermal.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/thermal/bcm2835-thermal.c 2014-02-07 19:57:29.000000000 +0100
-@@ -0,0 +1,184 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/sysfs.h>
-+#include <mach/vcio.h>
-+#include <linux/thermal.h>
-+
-+
-+/* --- DEFINITIONS --- */
-+#define MODULE_NAME "bcm2835_thermal"
-+
-+/*#define THERMAL_DEBUG_ENABLE*/
-+
-+#ifdef THERMAL_DEBUG_ENABLE
-+#define print_debug(fmt,...) printk(KERN_INFO "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
-+#else
-+#define print_debug(fmt,...)
-+#endif
-+#define print_err(fmt,...) printk(KERN_ERR "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
-+
-+#define VC_TAG_GET_TEMP 0x00030006
-+#define VC_TAG_GET_MAX_TEMP 0x0003000A
-+
-+typedef enum {
-+ TEMP,
-+ MAX_TEMP,
-+} temp_type;
-+
-+/* --- STRUCTS --- */
-+/* tag part of the message */
-+struct vc_msg_tag {
-+ uint32_t tag_id; /* the tag ID for the temperature */
-+ uint32_t buffer_size; /* size of the buffer (should be 8) */
-+ uint32_t request_code; /* identifies message as a request (should be 0) */
-+ uint32_t id; /* extra ID field (should be 0) */
-+ uint32_t val; /* returned value of the temperature */
-+};
-+
-+/* message structure to be sent to videocore */
-+struct vc_msg {
-+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
-+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
-+ struct vc_msg_tag tag; /* the tag structure above to make */
-+ uint32_t end_tag; /* an end identifier, should be set to NULL */
-+};
-+
-+struct bcm2835_thermal_data {
-+ struct thermal_zone_device *thermal_dev;
-+ struct vc_msg msg;
-+};
-+
-+/* --- GLOBALS --- */
-+static struct bcm2835_thermal_data bcm2835_data;
-+
-+/* Thermal Device Operations */
-+static struct thermal_zone_device_ops ops;
-+
-+/* --- FUNCTIONS --- */
-+
-+static int bcm2835_get_temp_or_max(struct thermal_zone_device *thermal_dev, unsigned long *temp, unsigned tag_id)
-+{
-+ int result = -1, retry = 3;
-+ print_debug("IN");
-+
-+ *temp = 0;
-+ while (result != 0 && retry-- > 0) {
-+ /* wipe all previous message data */
-+ memset(&bcm2835_data.msg, 0, sizeof bcm2835_data.msg);
-+
-+ /* prepare message */
-+ bcm2835_data.msg.msg_size = sizeof bcm2835_data.msg;
-+ bcm2835_data.msg.tag.buffer_size = 8;
-+ bcm2835_data.msg.tag.tag_id = tag_id;
-+
-+ /* send the message */
-+ result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg);
-+ print_debug("Got %stemperature as %u (%d,%x)\n", tag_id==VC_TAG_GET_MAX_TEMP ? "max ":"", (uint)bcm2835_data.msg.tag.val, result, bcm2835_data.msg.request_code);
-+ if (!(bcm2835_data.msg.request_code & 0x80000000))
-+ result = -1;
-+ }
-+
-+ /* check if it was all ok and return the rate in milli degrees C */
-+ if (result == 0)
-+ *temp = (uint)bcm2835_data.msg.tag.val;
-+ else
-+ print_err("Failed to get temperature! (%x:%d)\n", tag_id, result);
-+ print_debug("OUT");
-+ return result;
-+}
-+
-+static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *temp)
-+{
-+ return bcm2835_get_temp_or_max(thermal_dev, temp, VC_TAG_GET_TEMP);
-+}
-+
-+static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int trip_num, unsigned long *temp)
-+{
-+ return bcm2835_get_temp_or_max(thermal_dev, temp, VC_TAG_GET_MAX_TEMP);
-+}
-+
-+static int bcm2835_get_trip_type(struct thermal_zone_device * thermal_dev, int trip_num, enum thermal_trip_type *trip_type)
-+{
-+ *trip_type = THERMAL_TRIP_HOT;
-+ return 0;
-+}
-+
-+
-+static int bcm2835_get_mode(struct thermal_zone_device *thermal_dev, enum thermal_device_mode *dev_mode)
-+{
-+ *dev_mode = THERMAL_DEVICE_ENABLED;
-+ return 0;
-+}
-+
-+
-+static int bcm2835_thermal_probe(struct platform_device *pdev)
-+{
-+ print_debug("IN");
-+ print_debug("THERMAL Driver has been probed!");
-+
-+ /* check that the device isn't null!*/
-+ if(pdev == NULL)
-+ {
-+ print_debug("Platform device is empty!");
-+ return -ENODEV;
-+ }
-+
-+ if(!(bcm2835_data.thermal_dev = thermal_zone_device_register("bcm2835_thermal", 1, 0, NULL, &ops, NULL, 0, 0)))
-+ {
-+ print_debug("Unable to register the thermal device!");
-+ return -EFAULT;
-+ }
-+ return 0;
-+}
-+
-+
-+static int bcm2835_thermal_remove(struct platform_device *pdev)
-+{
-+ print_debug("IN");
-+
-+ thermal_zone_device_unregister(bcm2835_data.thermal_dev);
-+
-+ print_debug("OUT");
-+
-+ return 0;
-+}
-+
-+static struct thermal_zone_device_ops ops = {
-+ .get_temp = bcm2835_get_temp,
-+ .get_trip_temp = bcm2835_get_max_temp,
-+ .get_trip_type = bcm2835_get_trip_type,
-+ .get_mode = bcm2835_get_mode,
-+};
-+
-+/* Thermal Driver */
-+static struct platform_driver bcm2835_thermal_driver = {
-+ .probe = bcm2835_thermal_probe,
-+ .remove = bcm2835_thermal_remove,
-+ .driver = {
-+ .name = "bcm2835_thermal",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Dorian Peake");
-+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
-+
-+module_platform_driver(bcm2835_thermal_driver);
-diff -Nur linux-3.11.10.orig/drivers/thermal/Kconfig linux-3.11.10/drivers/thermal/Kconfig
---- linux-3.11.10.orig/drivers/thermal/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/thermal/Kconfig 2014-02-07 19:57:29.000000000 +0100
-@@ -169,6 +169,12 @@
- enforce idle time which results in more package C-state residency. The
- user interface is exposed via generic thermal framework.
-
-+config THERMAL_BCM2835
-+ tristate "BCM2835 Thermal Driver"
-+ help
-+ This will enable temperature monitoring for the Broadcom BCM2835
-+ chip. If built as a module, it will be called 'bcm2835-thermal'.
-+
- config X86_PKG_TEMP_THERMAL
- tristate "X86 package temperature thermal driver"
- depends on X86_THERMAL_VECTOR
-diff -Nur linux-3.11.10.orig/drivers/thermal/Makefile linux-3.11.10/drivers/thermal/Makefile
---- linux-3.11.10.orig/drivers/thermal/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/thermal/Makefile 2014-02-07 19:57:29.000000000 +0100
-@@ -23,5 +23,6 @@
- obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
- obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
- obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
-+obj-$(CONFIG_THERMAL_BCM2835) += bcm2835-thermal.o
- obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
- obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
-diff -Nur linux-3.11.10.orig/drivers/tty/serial/amba-pl011.c linux-3.11.10/drivers/tty/serial/amba-pl011.c
---- linux-3.11.10.orig/drivers/tty/serial/amba-pl011.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/tty/serial/amba-pl011.c 2014-02-07 19:57:29.000000000 +0100
-@@ -84,7 +84,7 @@
-
- static unsigned int get_fifosize_arm(struct amba_device *dev)
- {
-- return amba_rev(dev) < 3 ? 16 : 32;
-+ return 16; //TODO: fix: amba_rev(dev) < 3 ? 16 : 32;
- }
-
- static struct vendor_data vendor_arm = {
-diff -Nur linux-3.11.10.orig/drivers/usb/core/generic.c linux-3.11.10/drivers/usb/core/generic.c
---- linux-3.11.10.orig/drivers/usb/core/generic.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/usb/core/generic.c 2014-02-07 19:57:30.000000000 +0100
-@@ -152,6 +152,7 @@
- dev_warn(&udev->dev,
- "no configuration chosen from %d choice%s\n",
- num_configs, plural(num_configs));
-+ dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
- }
- return i;
- }
-diff -Nur linux-3.11.10.orig/drivers/usb/core/message.c linux-3.11.10/drivers/usb/core/message.c
---- linux-3.11.10.orig/drivers/usb/core/message.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/usb/core/message.c 2014-02-07 19:57:30.000000000 +0100
-@@ -1875,6 +1875,85 @@
- if (cp->string == NULL &&
- !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
- cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
-+/* Uncomment this define to enable the HS Electrical Test support */
-+#define DWC_HS_ELECT_TST 1
-+#ifdef DWC_HS_ELECT_TST
-+ /* Here we implement the HS Electrical Test support. The
-+ * tester uses a vendor ID of 0x1A0A to indicate we should
-+ * run a special test sequence. The product ID tells us
-+ * which sequence to run. We invoke the test sequence by
-+ * sending a non-standard SetFeature command to our root
-+ * hub port. Our dwc_otg_hcd_hub_control() routine will
-+ * recognize the command and perform the desired test
-+ * sequence.
-+ */
-+ if (dev->descriptor.idVendor == 0x1A0A) {
-+ /* HSOTG Electrical Test */
-+ dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
-+
-+ if (dev->bus && dev->bus->root_hub) {
-+ struct usb_device *hdev = dev->bus->root_hub;
-+ dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
-+
-+ switch (dev->descriptor.idProduct) {
-+ case 0x0101: /* TEST_SE0_NAK */
-+ dev_warn(&dev->dev, "TEST_SE0_NAK\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
-+ break;
-+
-+ case 0x0102: /* TEST_J */
-+ dev_warn(&dev->dev, "TEST_J\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
-+ break;
-+
-+ case 0x0103: /* TEST_K */
-+ dev_warn(&dev->dev, "TEST_K\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
-+ break;
-+
-+ case 0x0104: /* TEST_PACKET */
-+ dev_warn(&dev->dev, "TEST_PACKET\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
-+ break;
-+
-+ case 0x0105: /* TEST_FORCE_ENABLE */
-+ dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
-+ break;
-+
-+ case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
-+ dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
-+ break;
-+
-+ case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
-+ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
-+ break;
-+
-+ case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
-+ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
-+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
-+ USB_REQ_SET_FEATURE, USB_RT_PORT,
-+ USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
-+ }
-+ }
-+ }
-+#endif /* DWC_HS_ELECT_TST */
-
- /* Now that the interfaces are installed, re-enable LPM. */
- usb_unlocked_enable_lpm(dev);
-diff -Nur linux-3.11.10.orig/drivers/usb/core/otg_whitelist.h linux-3.11.10/drivers/usb/core/otg_whitelist.h
---- linux-3.11.10.orig/drivers/usb/core/otg_whitelist.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/usb/core/otg_whitelist.h 2014-02-07 19:57:30.000000000 +0100
-@@ -19,33 +19,82 @@
- static struct usb_device_id whitelist_table [] = {
-
- /* hubs are optional in OTG, but very handy ... */
-+#define CERT_WITHOUT_HUBS
-+#if defined(CERT_WITHOUT_HUBS)
-+{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
-+#else
- { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
- { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
-+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
-+#endif
-
- #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
- /* FIXME actually, printers are NOT supposed to use device classes;
- * they're supposed to use interface classes...
- */
--{ USB_DEVICE_INFO(7, 1, 1) },
--{ USB_DEVICE_INFO(7, 1, 2) },
--{ USB_DEVICE_INFO(7, 1, 3) },
-+//{ USB_DEVICE_INFO(7, 1, 1) },
-+//{ USB_DEVICE_INFO(7, 1, 2) },
-+//{ USB_DEVICE_INFO(7, 1, 3) },
- #endif
-
- #ifdef CONFIG_USB_NET_CDCETHER
- /* Linux-USB CDC Ethernet gadget */
--{ USB_DEVICE(0x0525, 0xa4a1), },
-+//{ USB_DEVICE(0x0525, 0xa4a1), },
- /* Linux-USB CDC Ethernet + RNDIS gadget */
--{ USB_DEVICE(0x0525, 0xa4a2), },
-+//{ USB_DEVICE(0x0525, 0xa4a2), },
- #endif
-
- #if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
- /* gadget zero, for testing */
--{ USB_DEVICE(0x0525, 0xa4a0), },
-+//{ USB_DEVICE(0x0525, 0xa4a0), },
- #endif
-
-+/* OPT Tester */
-+{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
-+{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
-+{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
-+{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
-+{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
-+{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
-+{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
-+{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
-+
-+/* Sony cameras */
-+{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
-+
-+/* Memory Devices */
-+//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
-+//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
-+//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
-+//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
-+{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
-+//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
-+
-+/* HP Printers */
-+//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
-+//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
-+
-+/* Speakers */
-+//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
-+//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
-+
- { } /* Terminating entry */
- };
-
-+static inline void report_errors(struct usb_device *dev)
-+{
-+ /* OTG MESSAGE: report errors here, customize to match your product */
-+ dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
-+ le16_to_cpu(dev->descriptor.idVendor),
-+ le16_to_cpu(dev->descriptor.idProduct));
-+ if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
-+ dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
-+ } else {
-+ dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
-+ }
-+}
-+
-+
- static int is_targeted(struct usb_device *dev)
- {
- struct usb_device_id *id = whitelist_table;
-@@ -55,58 +104,83 @@
- return 1;
-
- /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
-- if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
-- le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
-- return 0;
-+ if (dev->descriptor.idVendor == 0x1a0a &&
-+ dev->descriptor.idProduct == 0xbadd) {
-+ return 0;
-+ } else if (!enable_whitelist) {
-+ return 1;
-+ } else {
-
-- /* NOTE: can't use usb_match_id() since interface caches
-- * aren't set up yet. this is cut/paste from that code.
-- */
-- for (id = whitelist_table; id->match_flags; id++) {
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
-- id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
-- continue;
--
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
-- id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
-- continue;
--
-- /* No need to test id->bcdDevice_lo != 0, since 0 is never
-- greater than any unsigned number. */
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
-- (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
-- continue;
--
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
-- (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
-- continue;
--
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
-- (id->bDeviceClass != dev->descriptor.bDeviceClass))
-- continue;
--
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
-- (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
-- continue;
--
-- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
-- (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
-- continue;
-+#ifdef DEBUG
-+ dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
-+ dev->descriptor.idVendor,
-+ dev->descriptor.idProduct,
-+ dev->descriptor.bDeviceClass,
-+ dev->descriptor.bDeviceSubClass,
-+ dev->descriptor.bDeviceProtocol);
-+#endif
-
- return 1;
-+ /* NOTE: can't use usb_match_id() since interface caches
-+ * aren't set up yet. this is cut/paste from that code.
-+ */
-+ for (id = whitelist_table; id->match_flags; id++) {
-+#ifdef DEBUG
-+ dev_dbg(&dev->dev,
-+ "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
-+ id->idVendor,
-+ id->idProduct,
-+ id->bDeviceClass,
-+ id->bDeviceSubClass,
-+ id->bDeviceProtocol);
-+#endif
-+
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
-+ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
-+ continue;
-+
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
-+ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
-+ continue;
-+
-+ /* No need to test id->bcdDevice_lo != 0, since 0 is never
-+ greater than any unsigned number. */
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
-+ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
-+ continue;
-+
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
-+ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
-+ continue;
-+
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
-+ (id->bDeviceClass != dev->descriptor.bDeviceClass))
-+ continue;
-+
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
-+ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
-+ continue;
-+
-+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
-+ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
-+ continue;
-+
-+ return 1;
-+ }
- }
-
- /* add other match criteria here ... */
-
--
-- /* OTG MESSAGE: report errors here, customize to match your product */
-- dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
-- le16_to_cpu(dev->descriptor.idVendor),
-- le16_to_cpu(dev->descriptor.idProduct));
- #ifdef CONFIG_USB_OTG_WHITELIST
-+ report_errors(dev);
- return 0;
- #else
-- return 1;
-+ if (enable_whitelist) {
-+ report_errors(dev);
-+ return 0;
-+ } else {
-+ return 1;
-+ }
- #endif
- }
-
-diff -Nur linux-3.11.10.orig/drivers/usb/gadget/file_storage.c linux-3.11.10/drivers/usb/gadget/file_storage.c
---- linux-3.11.10.orig/drivers/usb/gadget/file_storage.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/gadget/file_storage.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,3676 @@
-+/*
-+ * file_storage.c -- File-backed USB Storage Gadget, for USB development
-+ *
-+ * Copyright (C) 2003-2008 Alan Stern
-+ * 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") as published by the Free Software
-+ * Foundation, either version 2 of that License or (at your option) any
-+ * later version.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+
-+/*
-+ * The File-backed Storage Gadget acts as a USB Mass Storage device,
-+ * appearing to the host as a disk drive or as a CD-ROM drive. In addition
-+ * to providing an example of a genuinely useful gadget driver for a USB
-+ * device, it also illustrates a technique of double-buffering for increased
-+ * throughput. Last but not least, it gives an easy way to probe the
-+ * behavior of the Mass Storage drivers in a USB host.
-+ *
-+ * Backing storage is provided by a regular file or a block device, specified
-+ * by the "file" module parameter. Access can be limited to read-only by
-+ * setting the optional "ro" module parameter. (For CD-ROM emulation,
-+ * access is always read-only.) The gadget will indicate that it has
-+ * removable media if the optional "removable" module parameter is set.
-+ *
-+ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
-+ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
-+ * by the optional "transport" module parameter. It also supports the
-+ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
-+ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
-+ * the optional "protocol" module parameter. In addition, the default
-+ * Vendor ID, Product ID, release number and serial number can be overridden.
-+ *
-+ * There is support for multiple logical units (LUNs), each of which has
-+ * its own backing file. The number of LUNs can be set using the optional
-+ * "luns" module parameter (anywhere from 1 to 8), and the corresponding
-+ * files are specified using comma-separated lists for "file" and "ro".
-+ * The default number of LUNs is taken from the number of "file" elements;
-+ * it is 1 if "file" is not given. If "removable" is not set then a backing
-+ * file must be specified for each LUN. If it is set, then an unspecified
-+ * or empty backing filename means the LUN's medium is not loaded. Ideally
-+ * each LUN would be settable independently as a disk drive or a CD-ROM
-+ * drive, but currently all LUNs have to be the same type. The CD-ROM
-+ * emulation includes a single data track and no audio tracks; hence there
-+ * need be only one backing file per LUN.
-+ *
-+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
-+ * needed (an interrupt-out endpoint is also needed for CBI). The memory
-+ * requirement amounts to two 16K buffers, size configurable by a parameter.
-+ * Support is included for both full-speed and high-speed operation.
-+ *
-+ * Note that the driver is slightly non-portable in that it assumes a
-+ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
-+ * interrupt-in endpoints. With most device controllers this isn't an
-+ * issue, but there may be some with hardware restrictions that prevent
-+ * a buffer from being used by more than one endpoint.
-+ *
-+ * Module options:
-+ *
-+ * file=filename[,filename...]
-+ * Required if "removable" is not set, names of
-+ * the files or block devices used for
-+ * backing storage
-+ * serial=HHHH... Required serial number (string of hex chars)
-+ * ro=b[,b...] Default false, booleans for read-only access
-+ * removable Default false, boolean for removable media
-+ * luns=N Default N = number of filenames, number of
-+ * LUNs to support
-+ * nofua=b[,b...] Default false, booleans for ignore FUA flag
-+ * in SCSI WRITE(10,12) commands
-+ * stall Default determined according to the type of
-+ * USB device controller (usually true),
-+ * boolean to permit the driver to halt
-+ * bulk endpoints
-+ * cdrom Default false, boolean for whether to emulate
-+ * a CD-ROM drive
-+ * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
-+ * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
-+ * ATAPI, QIC, UFI, 8070, or SCSI;
-+ * also 1 - 6)
-+ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
-+ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
-+ * release=0xRRRR Override the USB release number (bcdDevice)
-+ * buflen=N Default N=16384, buffer size used (will be
-+ * rounded down to a multiple of
-+ * PAGE_CACHE_SIZE)
-+ *
-+ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
-+ * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
-+ * default values are used for everything else.
-+ *
-+ * The pathnames of the backing files and the ro settings are available in
-+ * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
-+ * the gadget's sysfs directory. If the "removable" option is set, writing to
-+ * these files will simulate ejecting/loading the medium (writing an empty
-+ * line means eject) and adjusting a write-enable tab. Changes to the ro
-+ * setting are not allowed when the medium is loaded or if CD-ROM emulation
-+ * is being used.
-+ *
-+ * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
-+ * The driver's SCSI command interface was based on the "Information
-+ * technology - Small Computer System Interface - 2" document from
-+ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
-+ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
-+ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
-+ * "Universal Serial Bus Mass Storage Class UFI Command Specification"
-+ * document, Revision 1.0, December 14, 1998, available at
-+ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
-+ */
-+
-+
-+/*
-+ * Driver Design
-+ *
-+ * The FSG driver is fairly straightforward. There is a main kernel
-+ * thread that handles most of the work. Interrupt routines field
-+ * callbacks from the controller driver: bulk- and interrupt-request
-+ * completion notifications, endpoint-0 events, and disconnect events.
-+ * Completion events are passed to the main thread by wakeup calls. Many
-+ * ep0 requests are handled at interrupt time, but SetInterface,
-+ * SetConfiguration, and device reset requests are forwarded to the
-+ * thread in the form of "exceptions" using SIGUSR1 signals (since they
-+ * should interrupt any ongoing file I/O operations).
-+ *
-+ * The thread's main routine implements the standard command/data/status
-+ * parts of a SCSI interaction. It and its subroutines are full of tests
-+ * for pending signals/exceptions -- all this polling is necessary since
-+ * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
-+ * indication that the driver really wants to be running in userspace.)
-+ * An important point is that so long as the thread is alive it keeps an
-+ * open reference to the backing file. This will prevent unmounting
-+ * the backing file's underlying filesystem and could cause problems
-+ * during system shutdown, for example. To prevent such problems, the
-+ * thread catches INT, TERM, and KILL signals and converts them into
-+ * an EXIT exception.
-+ *
-+ * In normal operation the main thread is started during the gadget's
-+ * fsg_bind() callback and stopped during fsg_unbind(). But it can also
-+ * exit when it receives a signal, and there's no point leaving the
-+ * gadget running when the thread is dead. So just before the thread
-+ * exits, it deregisters the gadget driver. This makes things a little
-+ * tricky: The driver is deregistered at two places, and the exiting
-+ * thread can indirectly call fsg_unbind() which in turn can tell the
-+ * thread to exit. The first problem is resolved through the use of the
-+ * REGISTERED atomic bitflag; the driver will only be deregistered once.
-+ * The second problem is resolved by having fsg_unbind() check
-+ * fsg->state; it won't try to stop the thread if the state is already
-+ * FSG_STATE_TERMINATED.
-+ *
-+ * To provide maximum throughput, the driver uses a circular pipeline of
-+ * buffer heads (struct fsg_buffhd). In principle the pipeline can be
-+ * arbitrarily long; in practice the benefits don't justify having more
-+ * than 2 stages (i.e., double buffering). But it helps to think of the
-+ * pipeline as being a long one. Each buffer head contains a bulk-in and
-+ * a bulk-out request pointer (since the buffer can be used for both
-+ * output and input -- directions always are given from the host's
-+ * point of view) as well as a pointer to the buffer and various state
-+ * variables.
-+ *
-+ * Use of the pipeline follows a simple protocol. There is a variable
-+ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
-+ * At any time that buffer head may still be in use from an earlier
-+ * request, so each buffer head has a state variable indicating whether
-+ * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
-+ * buffer head to be EMPTY, filling the buffer either by file I/O or by
-+ * USB I/O (during which the buffer head is BUSY), and marking the buffer
-+ * head FULL when the I/O is complete. Then the buffer will be emptied
-+ * (again possibly by USB I/O, during which it is marked BUSY) and
-+ * finally marked EMPTY again (possibly by a completion routine).
-+ *
-+ * A module parameter tells the driver to avoid stalling the bulk
-+ * endpoints wherever the transport specification allows. This is
-+ * necessary for some UDCs like the SuperH, which cannot reliably clear a
-+ * halt on a bulk endpoint. However, under certain circumstances the
-+ * Bulk-only specification requires a stall. In such cases the driver
-+ * will halt the endpoint and set a flag indicating that it should clear
-+ * the halt in software during the next device reset. Hopefully this
-+ * will permit everything to work correctly. Furthermore, although the
-+ * specification allows the bulk-out endpoint to halt when the host sends
-+ * too much data, implementing this would cause an unavoidable race.
-+ * The driver will always use the "no-stall" approach for OUT transfers.
-+ *
-+ * One subtle point concerns sending status-stage responses for ep0
-+ * requests. Some of these requests, such as device reset, can involve
-+ * interrupting an ongoing file I/O operation, which might take an
-+ * arbitrarily long time. During that delay the host might give up on
-+ * the original ep0 request and issue a new one. When that happens the
-+ * driver should not notify the host about completion of the original
-+ * request, as the host will no longer be waiting for it. So the driver
-+ * assigns to each ep0 request a unique tag, and it keeps track of the
-+ * tag value of the request associated with a long-running exception
-+ * (device-reset, interface-change, or configuration-change). When the
-+ * exception handler is finished, the status-stage response is submitted
-+ * only if the current ep0 request tag is equal to the exception request
-+ * tag. Thus only the most recently received ep0 request will get a
-+ * status-stage response.
-+ *
-+ * Warning: This driver source file is too long. It ought to be split up
-+ * into a header file plus about 3 separate .c files, to handle the details
-+ * of the Gadget, USB Mass Storage, and SCSI protocols.
-+ */
-+
-+
-+/* #define VERBOSE_DEBUG */
-+/* #define DUMP_MSGS */
-+
-+
-+#include <linux/blkdev.h>
-+#include <linux/completion.h>
-+#include <linux/dcache.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/fcntl.h>
-+#include <linux/file.h>
-+#include <linux/fs.h>
-+#include <linux/kref.h>
-+#include <linux/kthread.h>
-+#include <linux/limits.h>
-+#include <linux/module.h>
-+#include <linux/rwsem.h>
-+#include <linux/slab.h>
-+#include <linux/spinlock.h>
-+#include <linux/string.h>
-+#include <linux/freezer.h>
-+#include <linux/utsname.h>
-+
-+#include <linux/usb/ch9.h>
-+#include <linux/usb/gadget.h>
-+
-+#include "gadget_chips.h"
-+
-+
-+
-+/*
-+ * Kbuild is not very cooperative with respect to linking separately
-+ * compiled library objects into one module. So for now we won't use
-+ * separate compilation ... ensuring init/exit sections work to shrink
-+ * the runtime footprint, and giving us at least some parts of what
-+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
-+ */
-+#include "usbstring.c"
-+#include "config.c"
-+#include "epautoconf.c"
-+
-+/*-------------------------------------------------------------------------*/
-+
-+#define DRIVER_DESC "File-backed Storage Gadget"
-+#define DRIVER_NAME "g_file_storage"
-+#define DRIVER_VERSION "1 September 2010"
-+
-+static char fsg_string_manufacturer[64];
-+static const char fsg_string_product[] = DRIVER_DESC;
-+static const char fsg_string_config[] = "Self-powered";
-+static const char fsg_string_interface[] = "Mass Storage";
-+
-+
-+#include "storage_common.c"
-+
-+
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_AUTHOR("Alan Stern");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+/*
-+ * This driver assumes self-powered hardware and has no way for users to
-+ * trigger remote wakeup. It uses autoconfiguration to select endpoints
-+ * and endpoint addresses.
-+ */
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+
-+/* Encapsulate the module parameter settings */
-+
-+static struct {
-+ char *file[FSG_MAX_LUNS];
-+ char *serial;
-+ bool ro[FSG_MAX_LUNS];
-+ bool nofua[FSG_MAX_LUNS];
-+ unsigned int num_filenames;
-+ unsigned int num_ros;
-+ unsigned int num_nofuas;
-+ unsigned int nluns;
-+
-+ bool removable;
-+ bool can_stall;
-+ bool cdrom;
-+
-+ char *transport_parm;
-+ char *protocol_parm;
-+ unsigned short vendor;
-+ unsigned short product;
-+ unsigned short release;
-+ unsigned int buflen;
-+
-+ int transport_type;
-+ char *transport_name;
-+ int protocol_type;
-+ char *protocol_name;
-+
-+} mod_data = { // Default values
-+ .transport_parm = "BBB",
-+ .protocol_parm = "SCSI",
-+ .removable = 0,
-+ .can_stall = 1,
-+ .cdrom = 0,
-+ .vendor = FSG_VENDOR_ID,
-+ .product = FSG_PRODUCT_ID,
-+ .release = 0xffff, // Use controller chip type
-+ .buflen = 16384,
-+ };
-+
-+
-+module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
-+ S_IRUGO);
-+MODULE_PARM_DESC(file, "names of backing files or devices");
-+
-+module_param_named(serial, mod_data.serial, charp, S_IRUGO);
-+MODULE_PARM_DESC(serial, "USB serial number");
-+
-+module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
-+MODULE_PARM_DESC(ro, "true to force read-only");
-+
-+module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
-+ S_IRUGO);
-+MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
-+
-+module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
-+MODULE_PARM_DESC(luns, "number of LUNs");
-+
-+module_param_named(removable, mod_data.removable, bool, S_IRUGO);
-+MODULE_PARM_DESC(removable, "true to simulate removable media");
-+
-+module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
-+MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
-+
-+module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
-+MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
-+
-+/* In the non-TEST version, only the module parameters listed above
-+ * are available. */
-+#ifdef CONFIG_USB_FILE_STORAGE_TEST
-+
-+module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
-+MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
-+
-+module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
-+MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
-+ "8070, or SCSI)");
-+
-+module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
-+MODULE_PARM_DESC(vendor, "USB Vendor ID");
-+
-+module_param_named(product, mod_data.product, ushort, S_IRUGO);
-+MODULE_PARM_DESC(product, "USB Product ID");
-+
-+module_param_named(release, mod_data.release, ushort, S_IRUGO);
-+MODULE_PARM_DESC(release, "USB release number");
-+
-+module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
-+MODULE_PARM_DESC(buflen, "I/O buffer size");
-+
-+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
-+
-+
-+/*
-+ * These definitions will permit the compiler to avoid generating code for
-+ * parts of the driver that aren't used in the non-TEST version. Even gcc
-+ * can recognize when a test of a constant expression yields a dead code
-+ * path.
-+ */
-+
-+#ifdef CONFIG_USB_FILE_STORAGE_TEST
-+
-+#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
-+#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
-+#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
-+
-+#else
-+
-+#define transport_is_bbb() 1
-+#define transport_is_cbi() 0
-+#define protocol_is_scsi() 1
-+
-+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+
-+struct fsg_dev {
-+ /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
-+ spinlock_t lock;
-+ struct usb_gadget *gadget;
-+
-+ /* filesem protects: backing files in use */
-+ struct rw_semaphore filesem;
-+
-+ /* reference counting: wait until all LUNs are released */
-+ struct kref ref;
-+
-+ struct usb_ep *ep0; // Handy copy of gadget->ep0
-+ struct usb_request *ep0req; // For control responses
-+ unsigned int ep0_req_tag;
-+ const char *ep0req_name;
-+
-+ struct usb_request *intreq; // For interrupt responses
-+ int intreq_busy;
-+ struct fsg_buffhd *intr_buffhd;
-+
-+ unsigned int bulk_out_maxpacket;
-+ enum fsg_state state; // For exception handling
-+ unsigned int exception_req_tag;
-+
-+ u8 config, new_config;
-+
-+ unsigned int running : 1;
-+ unsigned int bulk_in_enabled : 1;
-+ unsigned int bulk_out_enabled : 1;
-+ unsigned int intr_in_enabled : 1;
-+ unsigned int phase_error : 1;
-+ unsigned int short_packet_received : 1;
-+ unsigned int bad_lun_okay : 1;
-+
-+ unsigned long atomic_bitflags;
-+#define REGISTERED 0
-+#define IGNORE_BULK_OUT 1
-+#define SUSPENDED 2
-+
-+ struct usb_ep *bulk_in;
-+ struct usb_ep *bulk_out;
-+ struct usb_ep *intr_in;
-+
-+ struct fsg_buffhd *next_buffhd_to_fill;
-+ struct fsg_buffhd *next_buffhd_to_drain;
-+
-+ int thread_wakeup_needed;
-+ struct completion thread_notifier;
-+ struct task_struct *thread_task;
-+
-+ int cmnd_size;
-+ u8 cmnd[MAX_COMMAND_SIZE];
-+ enum data_direction data_dir;
-+ u32 data_size;
-+ u32 data_size_from_cmnd;
-+ u32 tag;
-+ unsigned int lun;
-+ u32 residue;
-+ u32 usb_amount_left;
-+
-+ /* The CB protocol offers no way for a host to know when a command
-+ * has completed. As a result the next command may arrive early,
-+ * and we will still have to handle it. For that reason we need
-+ * a buffer to store new commands when using CB (or CBI, which
-+ * does not oblige a host to wait for command completion either). */
-+ int cbbuf_cmnd_size;
-+ u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
-+
-+ unsigned int nluns;
-+ struct fsg_lun *luns;
-+ struct fsg_lun *curlun;
-+ /* Must be the last entry */
-+ struct fsg_buffhd buffhds[];
-+};
-+
-+typedef void (*fsg_routine_t)(struct fsg_dev *);
-+
-+static int exception_in_progress(struct fsg_dev *fsg)
-+{
-+ return (fsg->state > FSG_STATE_IDLE);
-+}
-+
-+/* Make bulk-out requests be divisible by the maxpacket size */
-+static void set_bulk_out_req_length(struct fsg_dev *fsg,
-+ struct fsg_buffhd *bh, unsigned int length)
-+{
-+ unsigned int rem;
-+
-+ bh->bulk_out_intended_length = length;
-+ rem = length % fsg->bulk_out_maxpacket;
-+ if (rem > 0)
-+ length += fsg->bulk_out_maxpacket - rem;
-+ bh->outreq->length = length;
-+}
-+
-+static struct fsg_dev *the_fsg;
-+static struct usb_gadget_driver fsg_driver;
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
-+{
-+ const char *name;
-+
-+ if (ep == fsg->bulk_in)
-+ name = "bulk-in";
-+ else if (ep == fsg->bulk_out)
-+ name = "bulk-out";
-+ else
-+ name = ep->name;
-+ DBG(fsg, "%s set halt\n", name);
-+ return usb_ep_set_halt(ep);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * DESCRIPTORS ... most are static, but strings and (full) configuration
-+ * descriptors are built on demand. Also the (static) config and interface
-+ * descriptors are adjusted during fsg_bind().
-+ */
-+
-+/* There is only one configuration. */
-+#define CONFIG_VALUE 1
-+
-+static struct usb_device_descriptor
-+device_desc = {
-+ .bLength = sizeof device_desc,
-+ .bDescriptorType = USB_DT_DEVICE,
-+
-+ .bcdUSB = cpu_to_le16(0x0200),
-+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
-+
-+ /* The next three values can be overridden by module parameters */
-+ .idVendor = cpu_to_le16(FSG_VENDOR_ID),
-+ .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
-+ .bcdDevice = cpu_to_le16(0xffff),
-+
-+ .iManufacturer = FSG_STRING_MANUFACTURER,
-+ .iProduct = FSG_STRING_PRODUCT,
-+ .iSerialNumber = FSG_STRING_SERIAL,
-+ .bNumConfigurations = 1,
-+};
-+
-+static struct usb_config_descriptor
-+config_desc = {
-+ .bLength = sizeof config_desc,
-+ .bDescriptorType = USB_DT_CONFIG,
-+
-+ /* wTotalLength computed by usb_gadget_config_buf() */
-+ .bNumInterfaces = 1,
-+ .bConfigurationValue = CONFIG_VALUE,
-+ .iConfiguration = FSG_STRING_CONFIG,
-+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
-+};
-+
-+
-+static struct usb_qualifier_descriptor
-+dev_qualifier = {
-+ .bLength = sizeof dev_qualifier,
-+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
-+
-+ .bcdUSB = cpu_to_le16(0x0200),
-+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
-+
-+ .bNumConfigurations = 1,
-+};
-+
-+static int populate_bos(struct fsg_dev *fsg, u8 *buf)
-+{
-+ memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
-+ buf += USB_DT_BOS_SIZE;
-+
-+ memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
-+ buf += USB_DT_USB_EXT_CAP_SIZE;
-+
-+ memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
-+
-+ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
-+ + USB_DT_USB_EXT_CAP_SIZE;
-+}
-+
-+/*
-+ * Config descriptors must agree with the code that sets configurations
-+ * and with code managing interfaces and their altsettings. They must
-+ * also handle different speeds and other-speed requests.
-+ */
-+static int populate_config_buf(struct usb_gadget *gadget,
-+ u8 *buf, u8 type, unsigned index)
-+{
-+ enum usb_device_speed speed = gadget->speed;
-+ int len;
-+ const struct usb_descriptor_header **function;
-+
-+ if (index > 0)
-+ return -EINVAL;
-+
-+ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
-+ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
-+ function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
-+ ? (const struct usb_descriptor_header **)fsg_hs_function
-+ : (const struct usb_descriptor_header **)fsg_fs_function;
-+
-+ /* for now, don't advertise srp-only devices */
-+ if (!gadget_is_otg(gadget))
-+ function++;
-+
-+ len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
-+ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
-+ return len;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* These routines may be called in process context or in_irq */
-+
-+/* Caller must hold fsg->lock */
-+static void wakeup_thread(struct fsg_dev *fsg)
-+{
-+ /* Tell the main thread that something has happened */
-+ fsg->thread_wakeup_needed = 1;
-+ if (fsg->thread_task)
-+ wake_up_process(fsg->thread_task);
-+}
-+
-+
-+static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
-+{
-+ unsigned long flags;
-+
-+ /* Do nothing if a higher-priority exception is already in progress.
-+ * If a lower-or-equal priority exception is in progress, preempt it
-+ * and notify the main thread by sending it a signal. */
-+ spin_lock_irqsave(&fsg->lock, flags);
-+ if (fsg->state <= new_state) {
-+ fsg->exception_req_tag = fsg->ep0_req_tag;
-+ fsg->state = new_state;
-+ if (fsg->thread_task)
-+ send_sig_info(SIGUSR1, SEND_SIG_FORCED,
-+ fsg->thread_task);
-+ }
-+ spin_unlock_irqrestore(&fsg->lock, flags);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* The disconnect callback and ep0 routines. These always run in_irq,
-+ * except that ep0_queue() is called in the main thread to acknowledge
-+ * completion of various requests: set config, set interface, and
-+ * Bulk-only device reset. */
-+
-+static void fsg_disconnect(struct usb_gadget *gadget)
-+{
-+ struct fsg_dev *fsg = get_gadget_data(gadget);
-+
-+ DBG(fsg, "disconnect or port reset\n");
-+ raise_exception(fsg, FSG_STATE_DISCONNECT);
-+}
-+
-+
-+static int ep0_queue(struct fsg_dev *fsg)
-+{
-+ int rc;
-+
-+ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
-+ if (rc != 0 && rc != -ESHUTDOWN) {
-+
-+ /* We can't do much more than wait for a reset */
-+ WARNING(fsg, "error in submission: %s --> %d\n",
-+ fsg->ep0->name, rc);
-+ }
-+ return rc;
-+}
-+
-+static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
-+{
-+ struct fsg_dev *fsg = ep->driver_data;
-+
-+ if (req->actual > 0)
-+ dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
-+ if (req->status || req->actual != req->length)
-+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
-+ req->status, req->actual, req->length);
-+ if (req->status == -ECONNRESET) // Request was cancelled
-+ usb_ep_fifo_flush(ep);
-+
-+ if (req->status == 0 && req->context)
-+ ((fsg_routine_t) (req->context))(fsg);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Bulk and interrupt endpoint completion handlers.
-+ * These always run in_irq. */
-+
-+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
-+{
-+ struct fsg_dev *fsg = ep->driver_data;
-+ struct fsg_buffhd *bh = req->context;
-+
-+ if (req->status || req->actual != req->length)
-+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
-+ req->status, req->actual, req->length);
-+ if (req->status == -ECONNRESET) // Request was cancelled
-+ usb_ep_fifo_flush(ep);
-+
-+ /* Hold the lock while we update the request and buffer states */
-+ smp_wmb();
-+ spin_lock(&fsg->lock);
-+ bh->inreq_busy = 0;
-+ bh->state = BUF_STATE_EMPTY;
-+ wakeup_thread(fsg);
-+ spin_unlock(&fsg->lock);
-+}
-+
-+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
-+{
-+ struct fsg_dev *fsg = ep->driver_data;
-+ struct fsg_buffhd *bh = req->context;
-+
-+ dump_msg(fsg, "bulk-out", req->buf, req->actual);
-+ if (req->status || req->actual != bh->bulk_out_intended_length)
-+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
-+ req->status, req->actual,
-+ bh->bulk_out_intended_length);
-+ if (req->status == -ECONNRESET) // Request was cancelled
-+ usb_ep_fifo_flush(ep);
-+
-+ /* Hold the lock while we update the request and buffer states */
-+ smp_wmb();
-+ spin_lock(&fsg->lock);
-+ bh->outreq_busy = 0;
-+ bh->state = BUF_STATE_FULL;
-+ wakeup_thread(fsg);
-+ spin_unlock(&fsg->lock);
-+}
-+
-+
-+#ifdef CONFIG_USB_FILE_STORAGE_TEST
-+static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
-+{
-+ struct fsg_dev *fsg = ep->driver_data;
-+ struct fsg_buffhd *bh = req->context;
-+
-+ if (req->status || req->actual != req->length)
-+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
-+ req->status, req->actual, req->length);
-+ if (req->status == -ECONNRESET) // Request was cancelled
-+ usb_ep_fifo_flush(ep);
-+
-+ /* Hold the lock while we update the request and buffer states */
-+ smp_wmb();
-+ spin_lock(&fsg->lock);
-+ fsg->intreq_busy = 0;
-+ bh->state = BUF_STATE_EMPTY;
-+ wakeup_thread(fsg);
-+ spin_unlock(&fsg->lock);
-+}
-+
-+#else
-+static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
-+{}
-+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Ep0 class-specific handlers. These always run in_irq. */
-+
-+#ifdef CONFIG_USB_FILE_STORAGE_TEST
-+static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct usb_request *req = fsg->ep0req;
-+ static u8 cbi_reset_cmnd[6] = {
-+ SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
-+
-+ /* Error in command transfer? */
-+ if (req->status || req->length != req->actual ||
-+ req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
-+
-+ /* Not all controllers allow a protocol stall after
-+ * receiving control-out data, but we'll try anyway. */
-+ fsg_set_halt(fsg, fsg->ep0);
-+ return; // Wait for reset
-+ }
-+
-+ /* Is it the special reset command? */
-+ if (req->actual >= sizeof cbi_reset_cmnd &&
-+ memcmp(req->buf, cbi_reset_cmnd,
-+ sizeof cbi_reset_cmnd) == 0) {
-+
-+ /* Raise an exception to stop the current operation
-+ * and reinitialize our state. */
-+ DBG(fsg, "cbi reset request\n");
-+ raise_exception(fsg, FSG_STATE_RESET);
-+ return;
-+ }
-+
-+ VDBG(fsg, "CB[I] accept device-specific command\n");
-+ spin_lock(&fsg->lock);
-+
-+ /* Save the command for later */
-+ if (fsg->cbbuf_cmnd_size)
-+ WARNING(fsg, "CB[I] overwriting previous command\n");
-+ fsg->cbbuf_cmnd_size = req->actual;
-+ memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
-+
-+ wakeup_thread(fsg);
-+ spin_unlock(&fsg->lock);
-+}
-+
-+#else
-+static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{}
-+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
-+
-+
-+static int class_setup_req(struct fsg_dev *fsg,
-+ const struct usb_ctrlrequest *ctrl)
-+{
-+ struct usb_request *req = fsg->ep0req;
-+ int value = -EOPNOTSUPP;
-+ u16 w_index = le16_to_cpu(ctrl->wIndex);
-+ u16 w_value = le16_to_cpu(ctrl->wValue);
-+ u16 w_length = le16_to_cpu(ctrl->wLength);
-+
-+ if (!fsg->config)
-+ return value;
-+
-+ /* Handle Bulk-only class-specific requests */
-+ if (transport_is_bbb()) {
-+ switch (ctrl->bRequest) {
-+
-+ case US_BULK_RESET_REQUEST:
-+ if (ctrl->bRequestType != (USB_DIR_OUT |
-+ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
-+ break;
-+ if (w_index != 0 || w_value != 0 || w_length != 0) {
-+ value = -EDOM;
-+ break;
-+ }
-+
-+ /* Raise an exception to stop the current operation
-+ * and reinitialize our state. */
-+ DBG(fsg, "bulk reset request\n");
-+ raise_exception(fsg, FSG_STATE_RESET);
-+ value = DELAYED_STATUS;
-+ break;
-+
-+ case US_BULK_GET_MAX_LUN:
-+ if (ctrl->bRequestType != (USB_DIR_IN |
-+ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
-+ break;
-+ if (w_index != 0 || w_value != 0 || w_length != 1) {
-+ value = -EDOM;
-+ break;
-+ }
-+ VDBG(fsg, "get max LUN\n");
-+ *(u8 *) req->buf = fsg->nluns - 1;
-+ value = 1;
-+ break;
-+ }
-+ }
-+
-+ /* Handle CBI class-specific requests */
-+ else {
-+ switch (ctrl->bRequest) {
-+
-+ case USB_CBI_ADSC_REQUEST:
-+ if (ctrl->bRequestType != (USB_DIR_OUT |
-+ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
-+ break;
-+ if (w_index != 0 || w_value != 0) {
-+ value = -EDOM;
-+ break;
-+ }
-+ if (w_length > MAX_COMMAND_SIZE) {
-+ value = -EOVERFLOW;
-+ break;
-+ }
-+ value = w_length;
-+ fsg->ep0req->context = received_cbi_adsc;
-+ break;
-+ }
-+ }
-+
-+ if (value == -EOPNOTSUPP)
-+ VDBG(fsg,
-+ "unknown class-specific control req "
-+ "%02x.%02x v%04x i%04x l%u\n",
-+ ctrl->bRequestType, ctrl->bRequest,
-+ le16_to_cpu(ctrl->wValue), w_index, w_length);
-+ return value;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Ep0 standard request handlers. These always run in_irq. */
-+
-+static int standard_setup_req(struct fsg_dev *fsg,
-+ const struct usb_ctrlrequest *ctrl)
-+{
-+ struct usb_request *req = fsg->ep0req;
-+ int value = -EOPNOTSUPP;
-+ u16 w_index = le16_to_cpu(ctrl->wIndex);
-+ u16 w_value = le16_to_cpu(ctrl->wValue);
-+
-+ /* Usually this just stores reply data in the pre-allocated ep0 buffer,
-+ * but config change events will also reconfigure hardware. */
-+ switch (ctrl->bRequest) {
-+
-+ case USB_REQ_GET_DESCRIPTOR:
-+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
-+ USB_RECIP_DEVICE))
-+ break;
-+ switch (w_value >> 8) {
-+
-+ case USB_DT_DEVICE:
-+ VDBG(fsg, "get device descriptor\n");
-+ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
-+ value = sizeof device_desc;
-+ memcpy(req->buf, &device_desc, value);
-+ break;
-+ case USB_DT_DEVICE_QUALIFIER:
-+ VDBG(fsg, "get device qualifier\n");
-+ if (!gadget_is_dualspeed(fsg->gadget) ||
-+ fsg->gadget->speed == USB_SPEED_SUPER)
-+ break;
-+ /*
-+ * Assume ep0 uses the same maxpacket value for both
-+ * speeds
-+ */
-+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
-+ value = sizeof dev_qualifier;
-+ memcpy(req->buf, &dev_qualifier, value);
-+ break;
-+
-+ case USB_DT_OTHER_SPEED_CONFIG:
-+ VDBG(fsg, "get other-speed config descriptor\n");
-+ if (!gadget_is_dualspeed(fsg->gadget) ||
-+ fsg->gadget->speed == USB_SPEED_SUPER)
-+ break;
-+ goto get_config;
-+ case USB_DT_CONFIG:
-+ VDBG(fsg, "get configuration descriptor\n");
-+get_config:
-+ value = populate_config_buf(fsg->gadget,
-+ req->buf,
-+ w_value >> 8,
-+ w_value & 0xff);
-+ break;
-+
-+ case USB_DT_STRING:
-+ VDBG(fsg, "get string descriptor\n");
-+
-+ /* wIndex == language code */
-+ value = usb_gadget_get_string(&fsg_stringtab,
-+ w_value & 0xff, req->buf);
-+ break;
-+
-+ case USB_DT_BOS:
-+ VDBG(fsg, "get bos descriptor\n");
-+
-+ if (gadget_is_superspeed(fsg->gadget))
-+ value = populate_bos(fsg, req->buf);
-+ break;
-+ }
-+
-+ break;
-+
-+ /* One config, two speeds */
-+ case USB_REQ_SET_CONFIGURATION:
-+ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
-+ USB_RECIP_DEVICE))
-+ break;
-+ VDBG(fsg, "set configuration\n");
-+ if (w_value == CONFIG_VALUE || w_value == 0) {
-+ fsg->new_config = w_value;
-+
-+ /* Raise an exception to wipe out previous transaction
-+ * state (queued bufs, etc) and set the new config. */
-+ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
-+ value = DELAYED_STATUS;
-+ }
-+ break;
-+ case USB_REQ_GET_CONFIGURATION:
-+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
-+ USB_RECIP_DEVICE))
-+ break;
-+ VDBG(fsg, "get configuration\n");
-+ *(u8 *) req->buf = fsg->config;
-+ value = 1;
-+ break;
-+
-+ case USB_REQ_SET_INTERFACE:
-+ if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
-+ USB_RECIP_INTERFACE))
-+ break;
-+ if (fsg->config && w_index == 0) {
-+
-+ /* Raise an exception to wipe out previous transaction
-+ * state (queued bufs, etc) and install the new
-+ * interface altsetting. */
-+ raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
-+ value = DELAYED_STATUS;
-+ }
-+ break;
-+ case USB_REQ_GET_INTERFACE:
-+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
-+ USB_RECIP_INTERFACE))
-+ break;
-+ if (!fsg->config)
-+ break;
-+ if (w_index != 0) {
-+ value = -EDOM;
-+ break;
-+ }
-+ VDBG(fsg, "get interface\n");
-+ *(u8 *) req->buf = 0;
-+ value = 1;
-+ break;
-+
-+ default:
-+ VDBG(fsg,
-+ "unknown control req %02x.%02x v%04x i%04x l%u\n",
-+ ctrl->bRequestType, ctrl->bRequest,
-+ w_value, w_index, le16_to_cpu(ctrl->wLength));
-+ }
-+
-+ return value;
-+}
-+
-+
-+static int fsg_setup(struct usb_gadget *gadget,
-+ const struct usb_ctrlrequest *ctrl)
-+{
-+ struct fsg_dev *fsg = get_gadget_data(gadget);
-+ int rc;
-+ int w_length = le16_to_cpu(ctrl->wLength);
-+
-+ ++fsg->ep0_req_tag; // Record arrival of a new request
-+ fsg->ep0req->context = NULL;
-+ fsg->ep0req->length = 0;
-+ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
-+
-+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
-+ rc = class_setup_req(fsg, ctrl);
-+ else
-+ rc = standard_setup_req(fsg, ctrl);
-+
-+ /* Respond with data/status or defer until later? */
-+ if (rc >= 0 && rc != DELAYED_STATUS) {
-+ rc = min(rc, w_length);
-+ fsg->ep0req->length = rc;
-+ fsg->ep0req->zero = rc < w_length;
-+ fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
-+ "ep0-in" : "ep0-out");
-+ rc = ep0_queue(fsg);
-+ }
-+
-+ /* Device either stalls (rc < 0) or reports success */
-+ return rc;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* All the following routines run in process context */
-+
-+
-+/* Use this for bulk or interrupt transfers, not ep0 */
-+static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
-+ struct usb_request *req, int *pbusy,
-+ enum fsg_buffer_state *state)
-+{
-+ int rc;
-+
-+ if (ep == fsg->bulk_in)
-+ dump_msg(fsg, "bulk-in", req->buf, req->length);
-+ else if (ep == fsg->intr_in)
-+ dump_msg(fsg, "intr-in", req->buf, req->length);
-+
-+ spin_lock_irq(&fsg->lock);
-+ *pbusy = 1;
-+ *state = BUF_STATE_BUSY;
-+ spin_unlock_irq(&fsg->lock);
-+ rc = usb_ep_queue(ep, req, GFP_KERNEL);
-+ if (rc != 0) {
-+ *pbusy = 0;
-+ *state = BUF_STATE_EMPTY;
-+
-+ /* We can't do much more than wait for a reset */
-+
-+ /* Note: currently the net2280 driver fails zero-length
-+ * submissions if DMA is enabled. */
-+ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
-+ req->length == 0))
-+ WARNING(fsg, "error in submission: %s --> %d\n",
-+ ep->name, rc);
-+ }
-+}
-+
-+
-+static int sleep_thread(struct fsg_dev *fsg)
-+{
-+ int rc = 0;
-+
-+ /* Wait until a signal arrives or we are woken up */
-+ for (;;) {
-+ try_to_freeze();
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (signal_pending(current)) {
-+ rc = -EINTR;
-+ break;
-+ }
-+ if (fsg->thread_wakeup_needed)
-+ break;
-+ schedule();
-+ }
-+ __set_current_state(TASK_RUNNING);
-+ fsg->thread_wakeup_needed = 0;
-+ return rc;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int do_read(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ u32 lba;
-+ struct fsg_buffhd *bh;
-+ int rc;
-+ u32 amount_left;
-+ loff_t file_offset, file_offset_tmp;
-+ unsigned int amount;
-+ ssize_t nread;
-+
-+ /* Get the starting Logical Block Address and check that it's
-+ * not too big */
-+ if (fsg->cmnd[0] == READ_6)
-+ lba = get_unaligned_be24(&fsg->cmnd[1]);
-+ else {
-+ lba = get_unaligned_be32(&fsg->cmnd[2]);
-+
-+ /* We allow DPO (Disable Page Out = don't save data in the
-+ * cache) and FUA (Force Unit Access = don't read from the
-+ * cache), but we don't implement them. */
-+ if ((fsg->cmnd[1] & ~0x18) != 0) {
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+ }
-+ if (lba >= curlun->num_sectors) {
-+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ return -EINVAL;
-+ }
-+ file_offset = ((loff_t) lba) << curlun->blkbits;
-+
-+ /* Carry out the file reads */
-+ amount_left = fsg->data_size_from_cmnd;
-+ if (unlikely(amount_left == 0))
-+ return -EIO; // No default reply
-+
-+ for (;;) {
-+
-+ /* Figure out how much we need to read:
-+ * Try to read the remaining amount.
-+ * But don't read more than the buffer size.
-+ * And don't try to read past the end of the file.
-+ */
-+ amount = min((unsigned int) amount_left, mod_data.buflen);
-+ amount = min((loff_t) amount,
-+ curlun->file_length - file_offset);
-+
-+ /* Wait for the next buffer to become available */
-+ bh = fsg->next_buffhd_to_fill;
-+ while (bh->state != BUF_STATE_EMPTY) {
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ /* If we were asked to read past the end of file,
-+ * end with an empty buffer. */
-+ if (amount == 0) {
-+ curlun->sense_data =
-+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ curlun->sense_data_info = file_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ bh->inreq->length = 0;
-+ bh->state = BUF_STATE_FULL;
-+ break;
-+ }
-+
-+ /* Perform the read */
-+ file_offset_tmp = file_offset;
-+ nread = vfs_read(curlun->filp,
-+ (char __user *) bh->buf,
-+ amount, &file_offset_tmp);
-+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
-+ (unsigned long long) file_offset,
-+ (int) nread);
-+ if (signal_pending(current))
-+ return -EINTR;
-+
-+ if (nread < 0) {
-+ LDBG(curlun, "error in file read: %d\n",
-+ (int) nread);
-+ nread = 0;
-+ } else if (nread < amount) {
-+ LDBG(curlun, "partial file read: %d/%u\n",
-+ (int) nread, amount);
-+ nread = round_down(nread, curlun->blksize);
-+ }
-+ file_offset += nread;
-+ amount_left -= nread;
-+ fsg->residue -= nread;
-+
-+ /* Except at the end of the transfer, nread will be
-+ * equal to the buffer size, which is divisible by the
-+ * bulk-in maxpacket size.
-+ */
-+ bh->inreq->length = nread;
-+ bh->state = BUF_STATE_FULL;
-+
-+ /* If an error occurred, report it and its position */
-+ if (nread < amount) {
-+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-+ curlun->sense_data_info = file_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ break;
-+ }
-+
-+ if (amount_left == 0)
-+ break; // No more left to read
-+
-+ /* Send this buffer and go read some more */
-+ bh->inreq->zero = 0;
-+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
-+ &bh->inreq_busy, &bh->state);
-+ fsg->next_buffhd_to_fill = bh->next;
-+ }
-+
-+ return -EIO; // No default reply
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int do_write(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ u32 lba;
-+ struct fsg_buffhd *bh;
-+ int get_some_more;
-+ u32 amount_left_to_req, amount_left_to_write;
-+ loff_t usb_offset, file_offset, file_offset_tmp;
-+ unsigned int amount;
-+ ssize_t nwritten;
-+ int rc;
-+
-+ if (curlun->ro) {
-+ curlun->sense_data = SS_WRITE_PROTECTED;
-+ return -EINVAL;
-+ }
-+ spin_lock(&curlun->filp->f_lock);
-+ curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
-+ spin_unlock(&curlun->filp->f_lock);
-+
-+ /* Get the starting Logical Block Address and check that it's
-+ * not too big */
-+ if (fsg->cmnd[0] == WRITE_6)
-+ lba = get_unaligned_be24(&fsg->cmnd[1]);
-+ else {
-+ lba = get_unaligned_be32(&fsg->cmnd[2]);
-+
-+ /* We allow DPO (Disable Page Out = don't save data in the
-+ * cache) and FUA (Force Unit Access = write directly to the
-+ * medium). We don't implement DPO; we implement FUA by
-+ * performing synchronous output. */
-+ if ((fsg->cmnd[1] & ~0x18) != 0) {
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+ /* FUA */
-+ if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
-+ spin_lock(&curlun->filp->f_lock);
-+ curlun->filp->f_flags |= O_DSYNC;
-+ spin_unlock(&curlun->filp->f_lock);
-+ }
-+ }
-+ if (lba >= curlun->num_sectors) {
-+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ return -EINVAL;
-+ }
-+
-+ /* Carry out the file writes */
-+ get_some_more = 1;
-+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
-+ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
-+
-+ while (amount_left_to_write > 0) {
-+
-+ /* Queue a request for more data from the host */
-+ bh = fsg->next_buffhd_to_fill;
-+ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
-+
-+ /* Figure out how much we want to get:
-+ * Try to get the remaining amount,
-+ * but not more than the buffer size.
-+ */
-+ amount = min(amount_left_to_req, mod_data.buflen);
-+
-+ /* Beyond the end of the backing file? */
-+ if (usb_offset >= curlun->file_length) {
-+ get_some_more = 0;
-+ curlun->sense_data =
-+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ curlun->sense_data_info = usb_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ continue;
-+ }
-+
-+ /* Get the next buffer */
-+ usb_offset += amount;
-+ fsg->usb_amount_left -= amount;
-+ amount_left_to_req -= amount;
-+ if (amount_left_to_req == 0)
-+ get_some_more = 0;
-+
-+ /* Except at the end of the transfer, amount will be
-+ * equal to the buffer size, which is divisible by
-+ * the bulk-out maxpacket size.
-+ */
-+ set_bulk_out_req_length(fsg, bh, amount);
-+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
-+ &bh->outreq_busy, &bh->state);
-+ fsg->next_buffhd_to_fill = bh->next;
-+ continue;
-+ }
-+
-+ /* Write the received data to the backing file */
-+ bh = fsg->next_buffhd_to_drain;
-+ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
-+ break; // We stopped early
-+ if (bh->state == BUF_STATE_FULL) {
-+ smp_rmb();
-+ fsg->next_buffhd_to_drain = bh->next;
-+ bh->state = BUF_STATE_EMPTY;
-+
-+ /* Did something go wrong with the transfer? */
-+ if (bh->outreq->status != 0) {
-+ curlun->sense_data = SS_COMMUNICATION_FAILURE;
-+ curlun->sense_data_info = file_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ break;
-+ }
-+
-+ amount = bh->outreq->actual;
-+ if (curlun->file_length - file_offset < amount) {
-+ LERROR(curlun,
-+ "write %u @ %llu beyond end %llu\n",
-+ amount, (unsigned long long) file_offset,
-+ (unsigned long long) curlun->file_length);
-+ amount = curlun->file_length - file_offset;
-+ }
-+
-+ /* Don't accept excess data. The spec doesn't say
-+ * what to do in this case. We'll ignore the error.
-+ */
-+ amount = min(amount, bh->bulk_out_intended_length);
-+
-+ /* Don't write a partial block */
-+ amount = round_down(amount, curlun->blksize);
-+ if (amount == 0)
-+ goto empty_write;
-+
-+ /* Perform the write */
-+ file_offset_tmp = file_offset;
-+ nwritten = vfs_write(curlun->filp,
-+ (char __user *) bh->buf,
-+ amount, &file_offset_tmp);
-+ VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
-+ (unsigned long long) file_offset,
-+ (int) nwritten);
-+ if (signal_pending(current))
-+ return -EINTR; // Interrupted!
-+
-+ if (nwritten < 0) {
-+ LDBG(curlun, "error in file write: %d\n",
-+ (int) nwritten);
-+ nwritten = 0;
-+ } else if (nwritten < amount) {
-+ LDBG(curlun, "partial file write: %d/%u\n",
-+ (int) nwritten, amount);
-+ nwritten = round_down(nwritten, curlun->blksize);
-+ }
-+ file_offset += nwritten;
-+ amount_left_to_write -= nwritten;
-+ fsg->residue -= nwritten;
-+
-+ /* If an error occurred, report it and its position */
-+ if (nwritten < amount) {
-+ curlun->sense_data = SS_WRITE_ERROR;
-+ curlun->sense_data_info = file_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ break;
-+ }
-+
-+ empty_write:
-+ /* Did the host decide to stop early? */
-+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
-+ fsg->short_packet_received = 1;
-+ break;
-+ }
-+ continue;
-+ }
-+
-+ /* Wait for something to happen */
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ return -EIO; // No default reply
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int do_synchronize_cache(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ int rc;
-+
-+ /* We ignore the requested LBA and write out all file's
-+ * dirty data buffers. */
-+ rc = fsg_lun_fsync_sub(curlun);
-+ if (rc)
-+ curlun->sense_data = SS_WRITE_ERROR;
-+ return 0;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void invalidate_sub(struct fsg_lun *curlun)
-+{
-+ struct file *filp = curlun->filp;
-+ struct inode *inode = filp->f_path.dentry->d_inode;
-+ unsigned long rc;
-+
-+ rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
-+ VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
-+}
-+
-+static int do_verify(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ u32 lba;
-+ u32 verification_length;
-+ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
-+ loff_t file_offset, file_offset_tmp;
-+ u32 amount_left;
-+ unsigned int amount;
-+ ssize_t nread;
-+
-+ /* Get the starting Logical Block Address and check that it's
-+ * not too big */
-+ lba = get_unaligned_be32(&fsg->cmnd[2]);
-+ if (lba >= curlun->num_sectors) {
-+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ return -EINVAL;
-+ }
-+
-+ /* We allow DPO (Disable Page Out = don't save data in the
-+ * cache) but we don't implement it. */
-+ if ((fsg->cmnd[1] & ~0x10) != 0) {
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+
-+ verification_length = get_unaligned_be16(&fsg->cmnd[7]);
-+ if (unlikely(verification_length == 0))
-+ return -EIO; // No default reply
-+
-+ /* Prepare to carry out the file verify */
-+ amount_left = verification_length << curlun->blkbits;
-+ file_offset = ((loff_t) lba) << curlun->blkbits;
-+
-+ /* Write out all the dirty buffers before invalidating them */
-+ fsg_lun_fsync_sub(curlun);
-+ if (signal_pending(current))
-+ return -EINTR;
-+
-+ invalidate_sub(curlun);
-+ if (signal_pending(current))
-+ return -EINTR;
-+
-+ /* Just try to read the requested blocks */
-+ while (amount_left > 0) {
-+
-+ /* Figure out how much we need to read:
-+ * Try to read the remaining amount, but not more than
-+ * the buffer size.
-+ * And don't try to read past the end of the file.
-+ */
-+ amount = min((unsigned int) amount_left, mod_data.buflen);
-+ amount = min((loff_t) amount,
-+ curlun->file_length - file_offset);
-+ if (amount == 0) {
-+ curlun->sense_data =
-+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ curlun->sense_data_info = file_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ break;
-+ }
-+
-+ /* Perform the read */
-+ file_offset_tmp = file_offset;
-+ nread = vfs_read(curlun->filp,
-+ (char __user *) bh->buf,
-+ amount, &file_offset_tmp);
-+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
-+ (unsigned long long) file_offset,
-+ (int) nread);
-+ if (signal_pending(current))
-+ return -EINTR;
-+
-+ if (nread < 0) {
-+ LDBG(curlun, "error in file verify: %d\n",
-+ (int) nread);
-+ nread = 0;
-+ } else if (nread < amount) {
-+ LDBG(curlun, "partial file verify: %d/%u\n",
-+ (int) nread, amount);
-+ nread = round_down(nread, curlun->blksize);
-+ }
-+ if (nread == 0) {
-+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-+ curlun->sense_data_info = file_offset >> curlun->blkbits;
-+ curlun->info_valid = 1;
-+ break;
-+ }
-+ file_offset += nread;
-+ amount_left -= nread;
-+ }
-+ return 0;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ u8 *buf = (u8 *) bh->buf;
-+
-+ static char vendor_id[] = "Linux ";
-+ static char product_disk_id[] = "File-Stor Gadget";
-+ static char product_cdrom_id[] = "File-CD Gadget ";
-+
-+ if (!fsg->curlun) { // Unsupported LUNs are okay
-+ fsg->bad_lun_okay = 1;
-+ memset(buf, 0, 36);
-+ buf[0] = 0x7f; // Unsupported, no device-type
-+ buf[4] = 31; // Additional length
-+ return 36;
-+ }
-+
-+ memset(buf, 0, 8);
-+ buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
-+ if (mod_data.removable)
-+ buf[1] = 0x80;
-+ buf[2] = 2; // ANSI SCSI level 2
-+ buf[3] = 2; // SCSI-2 INQUIRY data format
-+ buf[4] = 31; // Additional length
-+ // No special options
-+ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
-+ (mod_data.cdrom ? product_cdrom_id :
-+ product_disk_id),
-+ mod_data.release);
-+ return 36;
-+}
-+
-+
-+static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ u8 *buf = (u8 *) bh->buf;
-+ u32 sd, sdinfo;
-+ int valid;
-+
-+ /*
-+ * From the SCSI-2 spec., section 7.9 (Unit attention condition):
-+ *
-+ * If a REQUEST SENSE command is received from an initiator
-+ * with a pending unit attention condition (before the target
-+ * generates the contingent allegiance condition), then the
-+ * target shall either:
-+ * a) report any pending sense data and preserve the unit
-+ * attention condition on the logical unit, or,
-+ * b) report the unit attention condition, may discard any
-+ * pending sense data, and clear the unit attention
-+ * condition on the logical unit for that initiator.
-+ *
-+ * FSG normally uses option a); enable this code to use option b).
-+ */
-+#if 0
-+ if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
-+ curlun->sense_data = curlun->unit_attention_data;
-+ curlun->unit_attention_data = SS_NO_SENSE;
-+ }
-+#endif
-+
-+ if (!curlun) { // Unsupported LUNs are okay
-+ fsg->bad_lun_okay = 1;
-+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
-+ sdinfo = 0;
-+ valid = 0;
-+ } else {
-+ sd = curlun->sense_data;
-+ sdinfo = curlun->sense_data_info;
-+ valid = curlun->info_valid << 7;
-+ curlun->sense_data = SS_NO_SENSE;
-+ curlun->sense_data_info = 0;
-+ curlun->info_valid = 0;
-+ }
-+
-+ memset(buf, 0, 18);
-+ buf[0] = valid | 0x70; // Valid, current error
-+ buf[2] = SK(sd);
-+ put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
-+ buf[7] = 18 - 8; // Additional sense length
-+ buf[12] = ASC(sd);
-+ buf[13] = ASCQ(sd);
-+ return 18;
-+}
-+
-+
-+static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
-+ int pmi = fsg->cmnd[8];
-+ u8 *buf = (u8 *) bh->buf;
-+
-+ /* Check the PMI and LBA fields */
-+ if (pmi > 1 || (pmi == 0 && lba != 0)) {
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+
-+ put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
-+ /* Max logical block */
-+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
-+ return 8;
-+}
-+
-+
-+static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ int msf = fsg->cmnd[1] & 0x02;
-+ u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
-+ u8 *buf = (u8 *) bh->buf;
-+
-+ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+ if (lba >= curlun->num_sectors) {
-+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-+ return -EINVAL;
-+ }
-+
-+ memset(buf, 0, 8);
-+ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
-+ store_cdrom_address(&buf[4], msf, lba);
-+ return 8;
-+}
-+
-+
-+static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ int msf = fsg->cmnd[1] & 0x02;
-+ int start_track = fsg->cmnd[6];
-+ u8 *buf = (u8 *) bh->buf;
-+
-+ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
-+ start_track > 1) {
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+
-+ memset(buf, 0, 20);
-+ buf[1] = (20-2); /* TOC data length */
-+ buf[2] = 1; /* First track number */
-+ buf[3] = 1; /* Last track number */
-+ buf[5] = 0x16; /* Data track, copying allowed */
-+ buf[6] = 0x01; /* Only track is number 1 */
-+ store_cdrom_address(&buf[8], msf, 0);
-+
-+ buf[13] = 0x16; /* Lead-out track is data */
-+ buf[14] = 0xAA; /* Lead-out track number */
-+ store_cdrom_address(&buf[16], msf, curlun->num_sectors);
-+ return 20;
-+}
-+
-+
-+static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ int mscmnd = fsg->cmnd[0];
-+ u8 *buf = (u8 *) bh->buf;
-+ u8 *buf0 = buf;
-+ int pc, page_code;
-+ int changeable_values, all_pages;
-+ int valid_page = 0;
-+ int len, limit;
-+
-+ if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+ pc = fsg->cmnd[2] >> 6;
-+ page_code = fsg->cmnd[2] & 0x3f;
-+ if (pc == 3) {
-+ curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
-+ return -EINVAL;
-+ }
-+ changeable_values = (pc == 1);
-+ all_pages = (page_code == 0x3f);
-+
-+ /* Write the mode parameter header. Fixed values are: default
-+ * medium type, no cache control (DPOFUA), and no block descriptors.
-+ * The only variable value is the WriteProtect bit. We will fill in
-+ * the mode data length later. */
-+ memset(buf, 0, 8);
-+ if (mscmnd == MODE_SENSE) {
-+ buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
-+ buf += 4;
-+ limit = 255;
-+ } else { // MODE_SENSE_10
-+ buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
-+ buf += 8;
-+ limit = 65535; // Should really be mod_data.buflen
-+ }
-+
-+ /* No block descriptors */
-+
-+ /* The mode pages, in numerical order. The only page we support
-+ * is the Caching page. */
-+ if (page_code == 0x08 || all_pages) {
-+ valid_page = 1;
-+ buf[0] = 0x08; // Page code
-+ buf[1] = 10; // Page length
-+ memset(buf+2, 0, 10); // None of the fields are changeable
-+
-+ if (!changeable_values) {
-+ buf[2] = 0x04; // Write cache enable,
-+ // Read cache not disabled
-+ // No cache retention priorities
-+ put_unaligned_be16(0xffff, &buf[4]);
-+ /* Don't disable prefetch */
-+ /* Minimum prefetch = 0 */
-+ put_unaligned_be16(0xffff, &buf[8]);
-+ /* Maximum prefetch */
-+ put_unaligned_be16(0xffff, &buf[10]);
-+ /* Maximum prefetch ceiling */
-+ }
-+ buf += 12;
-+ }
-+
-+ /* Check that a valid page was requested and the mode data length
-+ * isn't too long. */
-+ len = buf - buf0;
-+ if (!valid_page || len > limit) {
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+
-+ /* Store the mode data length */
-+ if (mscmnd == MODE_SENSE)
-+ buf0[0] = len - 1;
-+ else
-+ put_unaligned_be16(len - 2, buf0);
-+ return len;
-+}
-+
-+
-+static int do_start_stop(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ int loej, start;
-+
-+ if (!mod_data.removable) {
-+ curlun->sense_data = SS_INVALID_COMMAND;
-+ return -EINVAL;
-+ }
-+
-+ // int immed = fsg->cmnd[1] & 0x01;
-+ loej = fsg->cmnd[4] & 0x02;
-+ start = fsg->cmnd[4] & 0x01;
-+
-+#ifdef CONFIG_USB_FILE_STORAGE_TEST
-+ if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
-+ (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+
-+ if (!start) {
-+
-+ /* Are we allowed to unload the media? */
-+ if (curlun->prevent_medium_removal) {
-+ LDBG(curlun, "unload attempt prevented\n");
-+ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
-+ return -EINVAL;
-+ }
-+ if (loej) { // Simulate an unload/eject
-+ up_read(&fsg->filesem);
-+ down_write(&fsg->filesem);
-+ fsg_lun_close(curlun);
-+ up_write(&fsg->filesem);
-+ down_read(&fsg->filesem);
-+ }
-+ } else {
-+
-+ /* Our emulation doesn't support mounting; the medium is
-+ * available for use as soon as it is loaded. */
-+ if (!fsg_lun_is_open(curlun)) {
-+ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
-+ return -EINVAL;
-+ }
-+ }
-+#endif
-+ return 0;
-+}
-+
-+
-+static int do_prevent_allow(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ int prevent;
-+
-+ if (!mod_data.removable) {
-+ curlun->sense_data = SS_INVALID_COMMAND;
-+ return -EINVAL;
-+ }
-+
-+ prevent = fsg->cmnd[4] & 0x01;
-+ if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+
-+ if (curlun->prevent_medium_removal && !prevent)
-+ fsg_lun_fsync_sub(curlun);
-+ curlun->prevent_medium_removal = prevent;
-+ return 0;
-+}
-+
-+
-+static int do_read_format_capacities(struct fsg_dev *fsg,
-+ struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ u8 *buf = (u8 *) bh->buf;
-+
-+ buf[0] = buf[1] = buf[2] = 0;
-+ buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
-+ buf += 4;
-+
-+ put_unaligned_be32(curlun->num_sectors, &buf[0]);
-+ /* Number of blocks */
-+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
-+ buf[4] = 0x02; /* Current capacity */
-+ return 12;
-+}
-+
-+
-+static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+
-+ /* We don't support MODE SELECT */
-+ curlun->sense_data = SS_INVALID_COMMAND;
-+ return -EINVAL;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
-+{
-+ int rc;
-+
-+ rc = fsg_set_halt(fsg, fsg->bulk_in);
-+ if (rc == -EAGAIN)
-+ VDBG(fsg, "delayed bulk-in endpoint halt\n");
-+ while (rc != 0) {
-+ if (rc != -EAGAIN) {
-+ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
-+ rc = 0;
-+ break;
-+ }
-+
-+ /* Wait for a short time and then try again */
-+ if (msleep_interruptible(100) != 0)
-+ return -EINTR;
-+ rc = usb_ep_set_halt(fsg->bulk_in);
-+ }
-+ return rc;
-+}
-+
-+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
-+{
-+ int rc;
-+
-+ DBG(fsg, "bulk-in set wedge\n");
-+ rc = usb_ep_set_wedge(fsg->bulk_in);
-+ if (rc == -EAGAIN)
-+ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
-+ while (rc != 0) {
-+ if (rc != -EAGAIN) {
-+ WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
-+ rc = 0;
-+ break;
-+ }
-+
-+ /* Wait for a short time and then try again */
-+ if (msleep_interruptible(100) != 0)
-+ return -EINTR;
-+ rc = usb_ep_set_wedge(fsg->bulk_in);
-+ }
-+ return rc;
-+}
-+
-+static int throw_away_data(struct fsg_dev *fsg)
-+{
-+ struct fsg_buffhd *bh;
-+ u32 amount;
-+ int rc;
-+
-+ while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
-+ fsg->usb_amount_left > 0) {
-+
-+ /* Throw away the data in a filled buffer */
-+ if (bh->state == BUF_STATE_FULL) {
-+ smp_rmb();
-+ bh->state = BUF_STATE_EMPTY;
-+ fsg->next_buffhd_to_drain = bh->next;
-+
-+ /* A short packet or an error ends everything */
-+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
-+ bh->outreq->status != 0) {
-+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
-+ return -EINTR;
-+ }
-+ continue;
-+ }
-+
-+ /* Try to submit another request if we need one */
-+ bh = fsg->next_buffhd_to_fill;
-+ if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
-+ amount = min(fsg->usb_amount_left,
-+ (u32) mod_data.buflen);
-+
-+ /* Except at the end of the transfer, amount will be
-+ * equal to the buffer size, which is divisible by
-+ * the bulk-out maxpacket size.
-+ */
-+ set_bulk_out_req_length(fsg, bh, amount);
-+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
-+ &bh->outreq_busy, &bh->state);
-+ fsg->next_buffhd_to_fill = bh->next;
-+ fsg->usb_amount_left -= amount;
-+ continue;
-+ }
-+
-+ /* Otherwise wait for something to happen */
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+ return 0;
-+}
-+
-+
-+static int finish_reply(struct fsg_dev *fsg)
-+{
-+ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
-+ int rc = 0;
-+
-+ switch (fsg->data_dir) {
-+ case DATA_DIR_NONE:
-+ break; // Nothing to send
-+
-+ /* If we don't know whether the host wants to read or write,
-+ * this must be CB or CBI with an unknown command. We mustn't
-+ * try to send or receive any data. So stall both bulk pipes
-+ * if we can and wait for a reset. */
-+ case DATA_DIR_UNKNOWN:
-+ if (mod_data.can_stall) {
-+ fsg_set_halt(fsg, fsg->bulk_out);
-+ rc = halt_bulk_in_endpoint(fsg);
-+ }
-+ break;
-+
-+ /* All but the last buffer of data must have already been sent */
-+ case DATA_DIR_TO_HOST:
-+ if (fsg->data_size == 0)
-+ ; // Nothing to send
-+
-+ /* If there's no residue, simply send the last buffer */
-+ else if (fsg->residue == 0) {
-+ bh->inreq->zero = 0;
-+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
-+ &bh->inreq_busy, &bh->state);
-+ fsg->next_buffhd_to_fill = bh->next;
-+ }
-+
-+ /* There is a residue. For CB and CBI, simply mark the end
-+ * of the data with a short packet. However, if we are
-+ * allowed to stall, there was no data at all (residue ==
-+ * data_size), and the command failed (invalid LUN or
-+ * sense data is set), then halt the bulk-in endpoint
-+ * instead. */
-+ else if (!transport_is_bbb()) {
-+ if (mod_data.can_stall &&
-+ fsg->residue == fsg->data_size &&
-+ (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
-+ bh->state = BUF_STATE_EMPTY;
-+ rc = halt_bulk_in_endpoint(fsg);
-+ } else {
-+ bh->inreq->zero = 1;
-+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
-+ &bh->inreq_busy, &bh->state);
-+ fsg->next_buffhd_to_fill = bh->next;
-+ }
-+ }
-+
-+ /*
-+ * For Bulk-only, mark the end of the data with a short
-+ * packet. If we are allowed to stall, halt the bulk-in
-+ * endpoint. (Note: This violates the Bulk-Only Transport
-+ * specification, which requires us to pad the data if we
-+ * don't halt the endpoint. Presumably nobody will mind.)
-+ */
-+ else {
-+ bh->inreq->zero = 1;
-+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
-+ &bh->inreq_busy, &bh->state);
-+ fsg->next_buffhd_to_fill = bh->next;
-+ if (mod_data.can_stall)
-+ rc = halt_bulk_in_endpoint(fsg);
-+ }
-+ break;
-+
-+ /* We have processed all we want from the data the host has sent.
-+ * There may still be outstanding bulk-out requests. */
-+ case DATA_DIR_FROM_HOST:
-+ if (fsg->residue == 0)
-+ ; // Nothing to receive
-+
-+ /* Did the host stop sending unexpectedly early? */
-+ else if (fsg->short_packet_received) {
-+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
-+ rc = -EINTR;
-+ }
-+
-+ /* We haven't processed all the incoming data. Even though
-+ * we may be allowed to stall, doing so would cause a race.
-+ * The controller may already have ACK'ed all the remaining
-+ * bulk-out packets, in which case the host wouldn't see a
-+ * STALL. Not realizing the endpoint was halted, it wouldn't
-+ * clear the halt -- leading to problems later on. */
-+#if 0
-+ else if (mod_data.can_stall) {
-+ fsg_set_halt(fsg, fsg->bulk_out);
-+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
-+ rc = -EINTR;
-+ }
-+#endif
-+
-+ /* We can't stall. Read in the excess data and throw it
-+ * all away. */
-+ else
-+ rc = throw_away_data(fsg);
-+ break;
-+ }
-+ return rc;
-+}
-+
-+
-+static int send_status(struct fsg_dev *fsg)
-+{
-+ struct fsg_lun *curlun = fsg->curlun;
-+ struct fsg_buffhd *bh;
-+ int rc;
-+ u8 status = US_BULK_STAT_OK;
-+ u32 sd, sdinfo = 0;
-+
-+ /* Wait for the next buffer to become available */
-+ bh = fsg->next_buffhd_to_fill;
-+ while (bh->state != BUF_STATE_EMPTY) {
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ if (curlun) {
-+ sd = curlun->sense_data;
-+ sdinfo = curlun->sense_data_info;
-+ } else if (fsg->bad_lun_okay)
-+ sd = SS_NO_SENSE;
-+ else
-+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
-+
-+ if (fsg->phase_error) {
-+ DBG(fsg, "sending phase-error status\n");
-+ status = US_BULK_STAT_PHASE;
-+ sd = SS_INVALID_COMMAND;
-+ } else if (sd != SS_NO_SENSE) {
-+ DBG(fsg, "sending command-failure status\n");
-+ status = US_BULK_STAT_FAIL;
-+ VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
-+ " info x%x\n",
-+ SK(sd), ASC(sd), ASCQ(sd), sdinfo);
-+ }
-+
-+ if (transport_is_bbb()) {
-+ struct bulk_cs_wrap *csw = bh->buf;
-+
-+ /* Store and send the Bulk-only CSW */
-+ csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
-+ csw->Tag = fsg->tag;
-+ csw->Residue = cpu_to_le32(fsg->residue);
-+ csw->Status = status;
-+
-+ bh->inreq->length = US_BULK_CS_WRAP_LEN;
-+ bh->inreq->zero = 0;
-+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
-+ &bh->inreq_busy, &bh->state);
-+
-+ } else if (mod_data.transport_type == USB_PR_CB) {
-+
-+ /* Control-Bulk transport has no status phase! */
-+ return 0;
-+
-+ } else { // USB_PR_CBI
-+ struct interrupt_data *buf = bh->buf;
-+
-+ /* Store and send the Interrupt data. UFI sends the ASC
-+ * and ASCQ bytes. Everything else sends a Type (which
-+ * is always 0) and the status Value. */
-+ if (mod_data.protocol_type == USB_SC_UFI) {
-+ buf->bType = ASC(sd);
-+ buf->bValue = ASCQ(sd);
-+ } else {
-+ buf->bType = 0;
-+ buf->bValue = status;
-+ }
-+ fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
-+
-+ fsg->intr_buffhd = bh; // Point to the right buffhd
-+ fsg->intreq->buf = bh->inreq->buf;
-+ fsg->intreq->context = bh;
-+ start_transfer(fsg, fsg->intr_in, fsg->intreq,
-+ &fsg->intreq_busy, &bh->state);
-+ }
-+
-+ fsg->next_buffhd_to_fill = bh->next;
-+ return 0;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Check whether the command is properly formed and whether its data size
-+ * and direction agree with the values we already have. */
-+static int check_command(struct fsg_dev *fsg, int cmnd_size,
-+ enum data_direction data_dir, unsigned int mask,
-+ int needs_medium, const char *name)
-+{
-+ int i;
-+ int lun = fsg->cmnd[1] >> 5;
-+ static const char dirletter[4] = {'u', 'o', 'i', 'n'};
-+ char hdlen[20];
-+ struct fsg_lun *curlun;
-+
-+ /* Adjust the expected cmnd_size for protocol encapsulation padding.
-+ * Transparent SCSI doesn't pad. */
-+ if (protocol_is_scsi())
-+ ;
-+
-+ /* There's some disagreement as to whether RBC pads commands or not.
-+ * We'll play it safe and accept either form. */
-+ else if (mod_data.protocol_type == USB_SC_RBC) {
-+ if (fsg->cmnd_size == 12)
-+ cmnd_size = 12;
-+
-+ /* All the other protocols pad to 12 bytes */
-+ } else
-+ cmnd_size = 12;
-+
-+ hdlen[0] = 0;
-+ if (fsg->data_dir != DATA_DIR_UNKNOWN)
-+ sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
-+ fsg->data_size);
-+ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
-+ name, cmnd_size, dirletter[(int) data_dir],
-+ fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
-+
-+ /* We can't reply at all until we know the correct data direction
-+ * and size. */
-+ if (fsg->data_size_from_cmnd == 0)
-+ data_dir = DATA_DIR_NONE;
-+ if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
-+ fsg->data_dir = data_dir;
-+ fsg->data_size = fsg->data_size_from_cmnd;
-+
-+ } else { // Bulk-only
-+ if (fsg->data_size < fsg->data_size_from_cmnd) {
-+
-+ /* Host data size < Device data size is a phase error.
-+ * Carry out the command, but only transfer as much
-+ * as we are allowed. */
-+ fsg->data_size_from_cmnd = fsg->data_size;
-+ fsg->phase_error = 1;
-+ }
-+ }
-+ fsg->residue = fsg->usb_amount_left = fsg->data_size;
-+
-+ /* Conflicting data directions is a phase error */
-+ if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
-+ fsg->phase_error = 1;
-+ return -EINVAL;
-+ }
-+
-+ /* Verify the length of the command itself */
-+ if (cmnd_size != fsg->cmnd_size) {
-+
-+ /* Special case workaround: There are plenty of buggy SCSI
-+ * implementations. Many have issues with cbw->Length
-+ * field passing a wrong command size. For those cases we
-+ * always try to work around the problem by using the length
-+ * sent by the host side provided it is at least as large
-+ * as the correct command length.
-+ * Examples of such cases would be MS-Windows, which issues
-+ * REQUEST SENSE with cbw->Length == 12 where it should
-+ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
-+ * REQUEST SENSE with cbw->Length == 10 where it should
-+ * be 6 as well.
-+ */
-+ if (cmnd_size <= fsg->cmnd_size) {
-+ DBG(fsg, "%s is buggy! Expected length %d "
-+ "but we got %d\n", name,
-+ cmnd_size, fsg->cmnd_size);
-+ cmnd_size = fsg->cmnd_size;
-+ } else {
-+ fsg->phase_error = 1;
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* Check that the LUN values are consistent */
-+ if (transport_is_bbb()) {
-+ if (fsg->lun != lun)
-+ DBG(fsg, "using LUN %d from CBW, "
-+ "not LUN %d from CDB\n",
-+ fsg->lun, lun);
-+ }
-+
-+ /* Check the LUN */
-+ curlun = fsg->curlun;
-+ if (curlun) {
-+ if (fsg->cmnd[0] != REQUEST_SENSE) {
-+ curlun->sense_data = SS_NO_SENSE;
-+ curlun->sense_data_info = 0;
-+ curlun->info_valid = 0;
-+ }
-+ } else {
-+ fsg->bad_lun_okay = 0;
-+
-+ /* INQUIRY and REQUEST SENSE commands are explicitly allowed
-+ * to use unsupported LUNs; all others may not. */
-+ if (fsg->cmnd[0] != INQUIRY &&
-+ fsg->cmnd[0] != REQUEST_SENSE) {
-+ DBG(fsg, "unsupported LUN %d\n", fsg->lun);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* If a unit attention condition exists, only INQUIRY and
-+ * REQUEST SENSE commands are allowed; anything else must fail. */
-+ if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
-+ fsg->cmnd[0] != INQUIRY &&
-+ fsg->cmnd[0] != REQUEST_SENSE) {
-+ curlun->sense_data = curlun->unit_attention_data;
-+ curlun->unit_attention_data = SS_NO_SENSE;
-+ return -EINVAL;
-+ }
-+
-+ /* Check that only command bytes listed in the mask are non-zero */
-+ fsg->cmnd[1] &= 0x1f; // Mask away the LUN
-+ for (i = 1; i < cmnd_size; ++i) {
-+ if (fsg->cmnd[i] && !(mask & (1 << i))) {
-+ if (curlun)
-+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* If the medium isn't mounted and the command needs to access
-+ * it, return an error. */
-+ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
-+ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/* wrapper of check_command for data size in blocks handling */
-+static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
-+ enum data_direction data_dir, unsigned int mask,
-+ int needs_medium, const char *name)
-+{
-+ if (fsg->curlun)
-+ fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
-+ return check_command(fsg, cmnd_size, data_dir,
-+ mask, needs_medium, name);
-+}
-+
-+static int do_scsi_command(struct fsg_dev *fsg)
-+{
-+ struct fsg_buffhd *bh;
-+ int rc;
-+ int reply = -EINVAL;
-+ int i;
-+ static char unknown[16];
-+
-+ dump_cdb(fsg);
-+
-+ /* Wait for the next buffer to become available for data or status */
-+ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
-+ while (bh->state != BUF_STATE_EMPTY) {
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+ fsg->phase_error = 0;
-+ fsg->short_packet_received = 0;
-+
-+ down_read(&fsg->filesem); // We're using the backing file
-+ switch (fsg->cmnd[0]) {
-+
-+ case INQUIRY:
-+ fsg->data_size_from_cmnd = fsg->cmnd[4];
-+ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
-+ (1<<4), 0,
-+ "INQUIRY")) == 0)
-+ reply = do_inquiry(fsg, bh);
-+ break;
-+
-+ case MODE_SELECT:
-+ fsg->data_size_from_cmnd = fsg->cmnd[4];
-+ if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
-+ (1<<1) | (1<<4), 0,
-+ "MODE SELECT(6)")) == 0)
-+ reply = do_mode_select(fsg, bh);
-+ break;
-+
-+ case MODE_SELECT_10:
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
-+ (1<<1) | (3<<7), 0,
-+ "MODE SELECT(10)")) == 0)
-+ reply = do_mode_select(fsg, bh);
-+ break;
-+
-+ case MODE_SENSE:
-+ fsg->data_size_from_cmnd = fsg->cmnd[4];
-+ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
-+ (1<<1) | (1<<2) | (1<<4), 0,
-+ "MODE SENSE(6)")) == 0)
-+ reply = do_mode_sense(fsg, bh);
-+ break;
-+
-+ case MODE_SENSE_10:
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
-+ (1<<1) | (1<<2) | (3<<7), 0,
-+ "MODE SENSE(10)")) == 0)
-+ reply = do_mode_sense(fsg, bh);
-+ break;
-+
-+ case ALLOW_MEDIUM_REMOVAL:
-+ fsg->data_size_from_cmnd = 0;
-+ if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
-+ (1<<4), 0,
-+ "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
-+ reply = do_prevent_allow(fsg);
-+ break;
-+
-+ case READ_6:
-+ i = fsg->cmnd[4];
-+ fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
-+ if ((reply = check_command_size_in_blocks(fsg, 6,
-+ DATA_DIR_TO_HOST,
-+ (7<<1) | (1<<4), 1,
-+ "READ(6)")) == 0)
-+ reply = do_read(fsg);
-+ break;
-+
-+ case READ_10:
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command_size_in_blocks(fsg, 10,
-+ DATA_DIR_TO_HOST,
-+ (1<<1) | (0xf<<2) | (3<<7), 1,
-+ "READ(10)")) == 0)
-+ reply = do_read(fsg);
-+ break;
-+
-+ case READ_12:
-+ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
-+ if ((reply = check_command_size_in_blocks(fsg, 12,
-+ DATA_DIR_TO_HOST,
-+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
-+ "READ(12)")) == 0)
-+ reply = do_read(fsg);
-+ break;
-+
-+ case READ_CAPACITY:
-+ fsg->data_size_from_cmnd = 8;
-+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
-+ (0xf<<2) | (1<<8), 1,
-+ "READ CAPACITY")) == 0)
-+ reply = do_read_capacity(fsg, bh);
-+ break;
-+
-+ case READ_HEADER:
-+ if (!mod_data.cdrom)
-+ goto unknown_cmnd;
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
-+ (3<<7) | (0x1f<<1), 1,
-+ "READ HEADER")) == 0)
-+ reply = do_read_header(fsg, bh);
-+ break;
-+
-+ case READ_TOC:
-+ if (!mod_data.cdrom)
-+ goto unknown_cmnd;
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
-+ (7<<6) | (1<<1), 1,
-+ "READ TOC")) == 0)
-+ reply = do_read_toc(fsg, bh);
-+ break;
-+
-+ case READ_FORMAT_CAPACITIES:
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
-+ (3<<7), 1,
-+ "READ FORMAT CAPACITIES")) == 0)
-+ reply = do_read_format_capacities(fsg, bh);
-+ break;
-+
-+ case REQUEST_SENSE:
-+ fsg->data_size_from_cmnd = fsg->cmnd[4];
-+ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
-+ (1<<4), 0,
-+ "REQUEST SENSE")) == 0)
-+ reply = do_request_sense(fsg, bh);
-+ break;
-+
-+ case START_STOP:
-+ fsg->data_size_from_cmnd = 0;
-+ if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
-+ (1<<1) | (1<<4), 0,
-+ "START-STOP UNIT")) == 0)
-+ reply = do_start_stop(fsg);
-+ break;
-+
-+ case SYNCHRONIZE_CACHE:
-+ fsg->data_size_from_cmnd = 0;
-+ if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
-+ (0xf<<2) | (3<<7), 1,
-+ "SYNCHRONIZE CACHE")) == 0)
-+ reply = do_synchronize_cache(fsg);
-+ break;
-+
-+ case TEST_UNIT_READY:
-+ fsg->data_size_from_cmnd = 0;
-+ reply = check_command(fsg, 6, DATA_DIR_NONE,
-+ 0, 1,
-+ "TEST UNIT READY");
-+ break;
-+
-+ /* Although optional, this command is used by MS-Windows. We
-+ * support a minimal version: BytChk must be 0. */
-+ case VERIFY:
-+ fsg->data_size_from_cmnd = 0;
-+ if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
-+ (1<<1) | (0xf<<2) | (3<<7), 1,
-+ "VERIFY")) == 0)
-+ reply = do_verify(fsg);
-+ break;
-+
-+ case WRITE_6:
-+ i = fsg->cmnd[4];
-+ fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
-+ if ((reply = check_command_size_in_blocks(fsg, 6,
-+ DATA_DIR_FROM_HOST,
-+ (7<<1) | (1<<4), 1,
-+ "WRITE(6)")) == 0)
-+ reply = do_write(fsg);
-+ break;
-+
-+ case WRITE_10:
-+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
-+ if ((reply = check_command_size_in_blocks(fsg, 10,
-+ DATA_DIR_FROM_HOST,
-+ (1<<1) | (0xf<<2) | (3<<7), 1,
-+ "WRITE(10)")) == 0)
-+ reply = do_write(fsg);
-+ break;
-+
-+ case WRITE_12:
-+ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
-+ if ((reply = check_command_size_in_blocks(fsg, 12,
-+ DATA_DIR_FROM_HOST,
-+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
-+ "WRITE(12)")) == 0)
-+ reply = do_write(fsg);
-+ break;
-+
-+ /* Some mandatory commands that we recognize but don't implement.
-+ * They don't mean much in this setting. It's left as an exercise
-+ * for anyone interested to implement RESERVE and RELEASE in terms
-+ * of Posix locks. */
-+ case FORMAT_UNIT:
-+ case RELEASE:
-+ case RESERVE:
-+ case SEND_DIAGNOSTIC:
-+ // Fall through
-+
-+ default:
-+ unknown_cmnd:
-+ fsg->data_size_from_cmnd = 0;
-+ sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
-+ if ((reply = check_command(fsg, fsg->cmnd_size,
-+ DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
-+ fsg->curlun->sense_data = SS_INVALID_COMMAND;
-+ reply = -EINVAL;
-+ }
-+ break;
-+ }
-+ up_read(&fsg->filesem);
-+
-+ if (reply == -EINTR || signal_pending(current))
-+ return -EINTR;
-+
-+ /* Set up the single reply buffer for finish_reply() */
-+ if (reply == -EINVAL)
-+ reply = 0; // Error reply length
-+ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
-+ reply = min((u32) reply, fsg->data_size_from_cmnd);
-+ bh->inreq->length = reply;
-+ bh->state = BUF_STATE_FULL;
-+ fsg->residue -= reply;
-+ } // Otherwise it's already set
-+
-+ return 0;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-+{
-+ struct usb_request *req = bh->outreq;
-+ struct bulk_cb_wrap *cbw = req->buf;
-+
-+ /* Was this a real packet? Should it be ignored? */
-+ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
-+ return -EINVAL;
-+
-+ /* Is the CBW valid? */
-+ if (req->actual != US_BULK_CB_WRAP_LEN ||
-+ cbw->Signature != cpu_to_le32(
-+ US_BULK_CB_SIGN)) {
-+ DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
-+ req->actual,
-+ le32_to_cpu(cbw->Signature));
-+
-+ /* The Bulk-only spec says we MUST stall the IN endpoint
-+ * (6.6.1), so it's unavoidable. It also says we must
-+ * retain this state until the next reset, but there's
-+ * no way to tell the controller driver it should ignore
-+ * Clear-Feature(HALT) requests.
-+ *
-+ * We aren't required to halt the OUT endpoint; instead
-+ * we can simply accept and discard any data received
-+ * until the next reset. */
-+ wedge_bulk_in_endpoint(fsg);
-+ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
-+ return -EINVAL;
-+ }
-+
-+ /* Is the CBW meaningful? */
-+ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
-+ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
-+ DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
-+ "cmdlen %u\n",
-+ cbw->Lun, cbw->Flags, cbw->Length);
-+
-+ /* We can do anything we want here, so let's stall the
-+ * bulk pipes if we are allowed to. */
-+ if (mod_data.can_stall) {
-+ fsg_set_halt(fsg, fsg->bulk_out);
-+ halt_bulk_in_endpoint(fsg);
-+ }
-+ return -EINVAL;
-+ }
-+
-+ /* Save the command for later */
-+ fsg->cmnd_size = cbw->Length;
-+ memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
-+ if (cbw->Flags & US_BULK_FLAG_IN)
-+ fsg->data_dir = DATA_DIR_TO_HOST;
-+ else
-+ fsg->data_dir = DATA_DIR_FROM_HOST;
-+ fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
-+ if (fsg->data_size == 0)
-+ fsg->data_dir = DATA_DIR_NONE;
-+ fsg->lun = cbw->Lun;
-+ fsg->tag = cbw->Tag;
-+ return 0;
-+}
-+
-+
-+static int get_next_command(struct fsg_dev *fsg)
-+{
-+ struct fsg_buffhd *bh;
-+ int rc = 0;
-+
-+ if (transport_is_bbb()) {
-+
-+ /* Wait for the next buffer to become available */
-+ bh = fsg->next_buffhd_to_fill;
-+ while (bh->state != BUF_STATE_EMPTY) {
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ /* Queue a request to read a Bulk-only CBW */
-+ set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
-+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
-+ &bh->outreq_busy, &bh->state);
-+
-+ /* We will drain the buffer in software, which means we
-+ * can reuse it for the next filling. No need to advance
-+ * next_buffhd_to_fill. */
-+
-+ /* Wait for the CBW to arrive */
-+ while (bh->state != BUF_STATE_FULL) {
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+ smp_rmb();
-+ rc = received_cbw(fsg, bh);
-+ bh->state = BUF_STATE_EMPTY;
-+
-+ } else { // USB_PR_CB or USB_PR_CBI
-+
-+ /* Wait for the next command to arrive */
-+ while (fsg->cbbuf_cmnd_size == 0) {
-+ rc = sleep_thread(fsg);
-+ if (rc)
-+ return rc;
-+ }
-+
-+ /* Is the previous status interrupt request still busy?
-+ * The host is allowed to skip reading the status,
-+ * so we must cancel it. */
-+ if (fsg->intreq_busy)
-+ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
-+
-+ /* Copy the command and mark the buffer empty */
-+ fsg->data_dir = DATA_DIR_UNKNOWN;
-+ spin_lock_irq(&fsg->lock);
-+ fsg->cmnd_size = fsg->cbbuf_cmnd_size;
-+ memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
-+ fsg->cbbuf_cmnd_size = 0;
-+ spin_unlock_irq(&fsg->lock);
-+
-+ /* Use LUN from the command */
-+ fsg->lun = fsg->cmnd[1] >> 5;
-+ }
-+
-+ /* Update current lun */
-+ if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
-+ fsg->curlun = &fsg->luns[fsg->lun];
-+ else
-+ fsg->curlun = NULL;
-+
-+ return rc;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
-+ const struct usb_endpoint_descriptor *d)
-+{
-+ int rc;
-+
-+ ep->driver_data = fsg;
-+ ep->desc = d;
-+ rc = usb_ep_enable(ep);
-+ if (rc)
-+ ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
-+ return rc;
-+}
-+
-+static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
-+ struct usb_request **preq)
-+{
-+ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
-+ if (*preq)
-+ return 0;
-+ ERROR(fsg, "can't allocate request for %s\n", ep->name);
-+ return -ENOMEM;
-+}
-+
-+/*
-+ * Reset interface setting and re-init endpoint state (toggle etc).
-+ * Call with altsetting < 0 to disable the interface. The only other
-+ * available altsetting is 0, which enables the interface.
-+ */
-+static int do_set_interface(struct fsg_dev *fsg, int altsetting)
-+{
-+ int rc = 0;
-+ int i;
-+ const struct usb_endpoint_descriptor *d;
-+
-+ if (fsg->running)
-+ DBG(fsg, "reset interface\n");
-+
-+reset:
-+ /* Deallocate the requests */
-+ for (i = 0; i < fsg_num_buffers; ++i) {
-+ struct fsg_buffhd *bh = &fsg->buffhds[i];
-+
-+ if (bh->inreq) {
-+ usb_ep_free_request(fsg->bulk_in, bh->inreq);
-+ bh->inreq = NULL;
-+ }
-+ if (bh->outreq) {
-+ usb_ep_free_request(fsg->bulk_out, bh->outreq);
-+ bh->outreq = NULL;
-+ }
-+ }
-+ if (fsg->intreq) {
-+ usb_ep_free_request(fsg->intr_in, fsg->intreq);
-+ fsg->intreq = NULL;
-+ }
-+
-+ /* Disable the endpoints */
-+ if (fsg->bulk_in_enabled) {
-+ usb_ep_disable(fsg->bulk_in);
-+ fsg->bulk_in_enabled = 0;
-+ }
-+ if (fsg->bulk_out_enabled) {
-+ usb_ep_disable(fsg->bulk_out);
-+ fsg->bulk_out_enabled = 0;
-+ }
-+ if (fsg->intr_in_enabled) {
-+ usb_ep_disable(fsg->intr_in);
-+ fsg->intr_in_enabled = 0;
-+ }
-+
-+ fsg->running = 0;
-+ if (altsetting < 0 || rc != 0)
-+ return rc;
-+
-+ DBG(fsg, "set interface %d\n", altsetting);
-+
-+ /* Enable the endpoints */
-+ d = fsg_ep_desc(fsg->gadget,
-+ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
-+ &fsg_ss_bulk_in_desc);
-+ if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
-+ goto reset;
-+ fsg->bulk_in_enabled = 1;
-+
-+ d = fsg_ep_desc(fsg->gadget,
-+ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
-+ &fsg_ss_bulk_out_desc);
-+ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
-+ goto reset;
-+ fsg->bulk_out_enabled = 1;
-+ fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
-+ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
-+
-+ if (transport_is_cbi()) {
-+ d = fsg_ep_desc(fsg->gadget,
-+ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
-+ &fsg_ss_intr_in_desc);
-+ if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
-+ goto reset;
-+ fsg->intr_in_enabled = 1;
-+ }
-+
-+ /* Allocate the requests */
-+ for (i = 0; i < fsg_num_buffers; ++i) {
-+ struct fsg_buffhd *bh = &fsg->buffhds[i];
-+
-+ if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
-+ goto reset;
-+ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
-+ goto reset;
-+ bh->inreq->buf = bh->outreq->buf = bh->buf;
-+ bh->inreq->context = bh->outreq->context = bh;
-+ bh->inreq->complete = bulk_in_complete;
-+ bh->outreq->complete = bulk_out_complete;
-+ }
-+ if (transport_is_cbi()) {
-+ if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
-+ goto reset;
-+ fsg->intreq->complete = intr_in_complete;
-+ }
-+
-+ fsg->running = 1;
-+ for (i = 0; i < fsg->nluns; ++i)
-+ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
-+ return rc;
-+}
-+
-+
-+/*
-+ * Change our operational configuration. This code must agree with the code
-+ * that returns config descriptors, and with interface altsetting code.
-+ *
-+ * It's also responsible for power management interactions. Some
-+ * configurations might not work with our current power sources.
-+ * For now we just assume the gadget is always self-powered.
-+ */
-+static int do_set_config(struct fsg_dev *fsg, u8 new_config)
-+{
-+ int rc = 0;
-+
-+ /* Disable the single interface */
-+ if (fsg->config != 0) {
-+ DBG(fsg, "reset config\n");
-+ fsg->config = 0;
-+ rc = do_set_interface(fsg, -1);
-+ }
-+
-+ /* Enable the interface */
-+ if (new_config != 0) {
-+ fsg->config = new_config;
-+ if ((rc = do_set_interface(fsg, 0)) != 0)
-+ fsg->config = 0; // Reset on errors
-+ else
-+ INFO(fsg, "%s config #%d\n",
-+ usb_speed_string(fsg->gadget->speed),
-+ fsg->config);
-+ }
-+ return rc;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void handle_exception(struct fsg_dev *fsg)
-+{
-+ siginfo_t info;
-+ int sig;
-+ int i;
-+ int num_active;
-+ struct fsg_buffhd *bh;
-+ enum fsg_state old_state;
-+ u8 new_config;
-+ struct fsg_lun *curlun;
-+ unsigned int exception_req_tag;
-+ int rc;
-+
-+ /* Clear the existing signals. Anything but SIGUSR1 is converted
-+ * into a high-priority EXIT exception. */
-+ for (;;) {
-+ sig = dequeue_signal_lock(current, &current->blocked, &info);
-+ if (!sig)
-+ break;
-+ if (sig != SIGUSR1) {
-+ if (fsg->state < FSG_STATE_EXIT)
-+ DBG(fsg, "Main thread exiting on signal\n");
-+ raise_exception(fsg, FSG_STATE_EXIT);
-+ }
-+ }
-+
-+ /* Cancel all the pending transfers */
-+ if (fsg->intreq_busy)
-+ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
-+ for (i = 0; i < fsg_num_buffers; ++i) {
-+ bh = &fsg->buffhds[i];
-+ if (bh->inreq_busy)
-+ usb_ep_dequeue(fsg->bulk_in, bh->inreq);
-+ if (bh->outreq_busy)
-+ usb_ep_dequeue(fsg->bulk_out, bh->outreq);
-+ }
-+
-+ /* Wait until everything is idle */
-+ for (;;) {
-+ num_active = fsg->intreq_busy;
-+ for (i = 0; i < fsg_num_buffers; ++i) {
-+ bh = &fsg->buffhds[i];
-+ num_active += bh->inreq_busy + bh->outreq_busy;
-+ }
-+ if (num_active == 0)
-+ break;
-+ if (sleep_thread(fsg))
-+ return;
-+ }
-+
-+ /* Clear out the controller's fifos */
-+ if (fsg->bulk_in_enabled)
-+ usb_ep_fifo_flush(fsg->bulk_in);
-+ if (fsg->bulk_out_enabled)
-+ usb_ep_fifo_flush(fsg->bulk_out);
-+ if (fsg->intr_in_enabled)
-+ usb_ep_fifo_flush(fsg->intr_in);
-+
-+ /* Reset the I/O buffer states and pointers, the SCSI
-+ * state, and the exception. Then invoke the handler. */
-+ spin_lock_irq(&fsg->lock);
-+
-+ for (i = 0; i < fsg_num_buffers; ++i) {
-+ bh = &fsg->buffhds[i];
-+ bh->state = BUF_STATE_EMPTY;
-+ }
-+ fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
-+ &fsg->buffhds[0];
-+
-+ exception_req_tag = fsg->exception_req_tag;
-+ new_config = fsg->new_config;
-+ old_state = fsg->state;
-+
-+ if (old_state == FSG_STATE_ABORT_BULK_OUT)
-+ fsg->state = FSG_STATE_STATUS_PHASE;
-+ else {
-+ for (i = 0; i < fsg->nluns; ++i) {
-+ curlun = &fsg->luns[i];
-+ curlun->prevent_medium_removal = 0;
-+ curlun->sense_data = curlun->unit_attention_data =
-+ SS_NO_SENSE;
-+ curlun->sense_data_info = 0;
-+ curlun->info_valid = 0;
-+ }
-+ fsg->state = FSG_STATE_IDLE;
-+ }
-+ spin_unlock_irq(&fsg->lock);
-+
-+ /* Carry out any extra actions required for the exception */
-+ switch (old_state) {
-+ default:
-+ break;
-+
-+ case FSG_STATE_ABORT_BULK_OUT:
-+ send_status(fsg);
-+ spin_lock_irq(&fsg->lock);
-+ if (fsg->state == FSG_STATE_STATUS_PHASE)
-+ fsg->state = FSG_STATE_IDLE;
-+ spin_unlock_irq(&fsg->lock);
-+ break;
-+
-+ case FSG_STATE_RESET:
-+ /* In case we were forced against our will to halt a
-+ * bulk endpoint, clear the halt now. (The SuperH UDC
-+ * requires this.) */
-+ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
-+ usb_ep_clear_halt(fsg->bulk_in);
-+
-+ if (transport_is_bbb()) {
-+ if (fsg->ep0_req_tag == exception_req_tag)
-+ ep0_queue(fsg); // Complete the status stage
-+
-+ } else if (transport_is_cbi())
-+ send_status(fsg); // Status by interrupt pipe
-+
-+ /* Technically this should go here, but it would only be
-+ * a waste of time. Ditto for the INTERFACE_CHANGE and
-+ * CONFIG_CHANGE cases. */
-+ // for (i = 0; i < fsg->nluns; ++i)
-+ // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
-+ break;
-+
-+ case FSG_STATE_INTERFACE_CHANGE:
-+ rc = do_set_interface(fsg, 0);
-+ if (fsg->ep0_req_tag != exception_req_tag)
-+ break;
-+ if (rc != 0) // STALL on errors
-+ fsg_set_halt(fsg, fsg->ep0);
-+ else // Complete the status stage
-+ ep0_queue(fsg);
-+ break;
-+
-+ case FSG_STATE_CONFIG_CHANGE:
-+ rc = do_set_config(fsg, new_config);
-+ if (fsg->ep0_req_tag != exception_req_tag)
-+ break;
-+ if (rc != 0) // STALL on errors
-+ fsg_set_halt(fsg, fsg->ep0);
-+ else // Complete the status stage
-+ ep0_queue(fsg);
-+ break;
-+
-+ case FSG_STATE_DISCONNECT:
-+ for (i = 0; i < fsg->nluns; ++i)
-+ fsg_lun_fsync_sub(fsg->luns + i);
-+ do_set_config(fsg, 0); // Unconfigured state
-+ break;
-+
-+ case FSG_STATE_EXIT:
-+ case FSG_STATE_TERMINATED:
-+ do_set_config(fsg, 0); // Free resources
-+ spin_lock_irq(&fsg->lock);
-+ fsg->state = FSG_STATE_TERMINATED; // Stop the thread
-+ spin_unlock_irq(&fsg->lock);
-+ break;
-+ }
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int fsg_main_thread(void *fsg_)
-+{
-+ struct fsg_dev *fsg = fsg_;
-+
-+ /* Allow the thread to be killed by a signal, but set the signal mask
-+ * to block everything but INT, TERM, KILL, and USR1. */
-+ allow_signal(SIGINT);
-+ allow_signal(SIGTERM);
-+ allow_signal(SIGKILL);
-+ allow_signal(SIGUSR1);
-+
-+ /* Allow the thread to be frozen */
-+ set_freezable();
-+
-+ /* Arrange for userspace references to be interpreted as kernel
-+ * pointers. That way we can pass a kernel pointer to a routine
-+ * that expects a __user pointer and it will work okay. */
-+ set_fs(get_ds());
-+
-+ /* The main loop */
-+ while (fsg->state != FSG_STATE_TERMINATED) {
-+ if (exception_in_progress(fsg) || signal_pending(current)) {
-+ handle_exception(fsg);
-+ continue;
-+ }
-+
-+ if (!fsg->running) {
-+ sleep_thread(fsg);
-+ continue;
-+ }
-+
-+ if (get_next_command(fsg))
-+ continue;
-+
-+ spin_lock_irq(&fsg->lock);
-+ if (!exception_in_progress(fsg))
-+ fsg->state = FSG_STATE_DATA_PHASE;
-+ spin_unlock_irq(&fsg->lock);
-+
-+ if (do_scsi_command(fsg) || finish_reply(fsg))
-+ continue;
-+
-+ spin_lock_irq(&fsg->lock);
-+ if (!exception_in_progress(fsg))
-+ fsg->state = FSG_STATE_STATUS_PHASE;
-+ spin_unlock_irq(&fsg->lock);
-+
-+ if (send_status(fsg))
-+ continue;
-+
-+ spin_lock_irq(&fsg->lock);
-+ if (!exception_in_progress(fsg))
-+ fsg->state = FSG_STATE_IDLE;
-+ spin_unlock_irq(&fsg->lock);
-+ }
-+
-+ spin_lock_irq(&fsg->lock);
-+ fsg->thread_task = NULL;
-+ spin_unlock_irq(&fsg->lock);
-+
-+ /* If we are exiting because of a signal, unregister the
-+ * gadget driver. */
-+ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
-+ usb_gadget_unregister_driver(&fsg_driver);
-+
-+ /* Let the unbind and cleanup routines know the thread has exited */
-+ complete_and_exit(&fsg->thread_notifier, 0);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+
-+/* The write permissions and store_xxx pointers are set in fsg_bind() */
-+static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
-+static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
-+static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void fsg_release(struct kref *ref)
-+{
-+ struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
-+
-+ kfree(fsg->luns);
-+ kfree(fsg);
-+}
-+
-+static void lun_release(struct device *dev)
-+{
-+ struct rw_semaphore *filesem = dev_get_drvdata(dev);
-+ struct fsg_dev *fsg =
-+ container_of(filesem, struct fsg_dev, filesem);
-+
-+ kref_put(&fsg->ref, fsg_release);
-+}
-+
-+static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
-+{
-+ struct fsg_dev *fsg = get_gadget_data(gadget);
-+ int i;
-+ struct fsg_lun *curlun;
-+ struct usb_request *req = fsg->ep0req;
-+
-+ DBG(fsg, "unbind\n");
-+ clear_bit(REGISTERED, &fsg->atomic_bitflags);
-+
-+ /* If the thread isn't already dead, tell it to exit now */
-+ if (fsg->state != FSG_STATE_TERMINATED) {
-+ raise_exception(fsg, FSG_STATE_EXIT);
-+ wait_for_completion(&fsg->thread_notifier);
-+
-+ /* The cleanup routine waits for this completion also */
-+ complete(&fsg->thread_notifier);
-+ }
-+
-+ /* Unregister the sysfs attribute files and the LUNs */
-+ for (i = 0; i < fsg->nluns; ++i) {
-+ curlun = &fsg->luns[i];
-+ if (curlun->registered) {
-+ device_remove_file(&curlun->dev, &dev_attr_nofua);
-+ device_remove_file(&curlun->dev, &dev_attr_ro);
-+ device_remove_file(&curlun->dev, &dev_attr_file);
-+ fsg_lun_close(curlun);
-+ device_unregister(&curlun->dev);
-+ curlun->registered = 0;
-+ }
-+ }
-+
-+ /* Free the data buffers */
-+ for (i = 0; i < fsg_num_buffers; ++i)
-+ kfree(fsg->buffhds[i].buf);
-+
-+ /* Free the request and buffer for endpoint 0 */
-+ if (req) {
-+ kfree(req->buf);
-+ usb_ep_free_request(fsg->ep0, req);
-+ }
-+
-+ set_gadget_data(gadget, NULL);
-+}
-+
-+
-+static int __init check_parameters(struct fsg_dev *fsg)
-+{
-+ int prot;
-+ int gcnum;
-+
-+ /* Store the default values */
-+ mod_data.transport_type = USB_PR_BULK;
-+ mod_data.transport_name = "Bulk-only";
-+ mod_data.protocol_type = USB_SC_SCSI;
-+ mod_data.protocol_name = "Transparent SCSI";
-+
-+ /* Some peripheral controllers are known not to be able to
-+ * halt bulk endpoints correctly. If one of them is present,
-+ * disable stalls.
-+ */
-+ if (gadget_is_at91(fsg->gadget))
-+ mod_data.can_stall = 0;
-+
-+ if (mod_data.release == 0xffff) { // Parameter wasn't set
-+ gcnum = usb_gadget_controller_number(fsg->gadget);
-+ if (gcnum >= 0)
-+ mod_data.release = 0x0300 + gcnum;
-+ else {
-+ WARNING(fsg, "controller '%s' not recognized\n",
-+ fsg->gadget->name);
-+ mod_data.release = 0x0399;
-+ }
-+ }
-+
-+ prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
-+
-+#ifdef CONFIG_USB_FILE_STORAGE_TEST
-+ if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
-+ ; // Use default setting
-+ } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
-+ mod_data.transport_type = USB_PR_CB;
-+ mod_data.transport_name = "Control-Bulk";
-+ } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
-+ mod_data.transport_type = USB_PR_CBI;
-+ mod_data.transport_name = "Control-Bulk-Interrupt";
-+ } else {
-+ ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
-+ return -EINVAL;
-+ }
-+
-+ if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
-+ prot == USB_SC_SCSI) {
-+ ; // Use default setting
-+ } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
-+ prot == USB_SC_RBC) {
-+ mod_data.protocol_type = USB_SC_RBC;
-+ mod_data.protocol_name = "RBC";
-+ } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
-+ strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
-+ prot == USB_SC_8020) {
-+ mod_data.protocol_type = USB_SC_8020;
-+ mod_data.protocol_name = "8020i (ATAPI)";
-+ } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
-+ prot == USB_SC_QIC) {
-+ mod_data.protocol_type = USB_SC_QIC;
-+ mod_data.protocol_name = "QIC-157";
-+ } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
-+ prot == USB_SC_UFI) {
-+ mod_data.protocol_type = USB_SC_UFI;
-+ mod_data.protocol_name = "UFI";
-+ } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
-+ prot == USB_SC_8070) {
-+ mod_data.protocol_type = USB_SC_8070;
-+ mod_data.protocol_name = "8070i";
-+ } else {
-+ ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
-+ return -EINVAL;
-+ }
-+
-+ mod_data.buflen &= PAGE_CACHE_MASK;
-+ if (mod_data.buflen <= 0) {
-+ ERROR(fsg, "invalid buflen\n");
-+ return -ETOOSMALL;
-+ }
-+
-+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
-+
-+ /* Serial string handling.
-+ * On a real device, the serial string would be loaded
-+ * from permanent storage. */
-+ if (mod_data.serial) {
-+ const char *ch;
-+ unsigned len = 0;
-+
-+ /* Sanity check :
-+ * The CB[I] specification limits the serial string to
-+ * 12 uppercase hexadecimal characters.
-+ * BBB need at least 12 uppercase hexadecimal characters,
-+ * with a maximum of 126. */
-+ for (ch = mod_data.serial; *ch; ++ch) {
-+ ++len;
-+ if ((*ch < '0' || *ch > '9') &&
-+ (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
-+ WARNING(fsg,
-+ "Invalid serial string character: %c\n",
-+ *ch);
-+ goto no_serial;
-+ }
-+ }
-+ if (len > 126 ||
-+ (mod_data.transport_type == USB_PR_BULK && len < 12) ||
-+ (mod_data.transport_type != USB_PR_BULK && len > 12)) {
-+ WARNING(fsg, "Invalid serial string length!\n");
-+ goto no_serial;
-+ }
-+ fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
-+ } else {
-+ WARNING(fsg, "No serial-number string provided!\n");
-+ no_serial:
-+ device_desc.iSerialNumber = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int __init fsg_bind(struct usb_gadget *gadget)
-+{
-+ struct fsg_dev *fsg = the_fsg;
-+ int rc;
-+ int i;
-+ struct fsg_lun *curlun;
-+ struct usb_ep *ep;
-+ struct usb_request *req;
-+ char *pathbuf, *p;
-+
-+ fsg->gadget = gadget;
-+ set_gadget_data(gadget, fsg);
-+ fsg->ep0 = gadget->ep0;
-+ fsg->ep0->driver_data = fsg;
-+
-+ if ((rc = check_parameters(fsg)) != 0)
-+ goto out;
-+
-+ if (mod_data.removable) { // Enable the store_xxx attributes
-+ dev_attr_file.attr.mode = 0644;
-+ dev_attr_file.store = fsg_store_file;
-+ if (!mod_data.cdrom) {
-+ dev_attr_ro.attr.mode = 0644;
-+ dev_attr_ro.store = fsg_store_ro;
-+ }
-+ }
-+
-+ /* Only for removable media? */
-+ dev_attr_nofua.attr.mode = 0644;
-+ dev_attr_nofua.store = fsg_store_nofua;
-+
-+ /* Find out how many LUNs there should be */
-+ i = mod_data.nluns;
-+ if (i == 0)
-+ i = max(mod_data.num_filenames, 1u);
-+ if (i > FSG_MAX_LUNS) {
-+ ERROR(fsg, "invalid number of LUNs: %d\n", i);
-+ rc = -EINVAL;
-+ goto out;
-+ }
-+
-+ /* Create the LUNs, open their backing files, and register the
-+ * LUN devices in sysfs. */
-+ fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
-+ if (!fsg->luns) {
-+ rc = -ENOMEM;
-+ goto out;
-+ }
-+ fsg->nluns = i;
-+
-+ for (i = 0; i < fsg->nluns; ++i) {
-+ curlun = &fsg->luns[i];
-+ curlun->cdrom = !!mod_data.cdrom;
-+ curlun->ro = mod_data.cdrom || mod_data.ro[i];
-+ curlun->initially_ro = curlun->ro;
-+ curlun->removable = mod_data.removable;
-+ curlun->nofua = mod_data.nofua[i];
-+ curlun->dev.release = lun_release;
-+ curlun->dev.parent = &gadget->dev;
-+ curlun->dev.driver = &fsg_driver.driver;
-+ dev_set_drvdata(&curlun->dev, &fsg->filesem);
-+ dev_set_name(&curlun->dev,"%s-lun%d",
-+ dev_name(&gadget->dev), i);
-+
-+ kref_get(&fsg->ref);
-+ rc = device_register(&curlun->dev);
-+ if (rc) {
-+ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
-+ put_device(&curlun->dev);
-+ goto out;
-+ }
-+ curlun->registered = 1;
-+
-+ rc = device_create_file(&curlun->dev, &dev_attr_ro);
-+ if (rc)
-+ goto out;
-+ rc = device_create_file(&curlun->dev, &dev_attr_nofua);
-+ if (rc)
-+ goto out;
-+ rc = device_create_file(&curlun->dev, &dev_attr_file);
-+ if (rc)
-+ goto out;
-+
-+ if (mod_data.file[i] && *mod_data.file[i]) {
-+ rc = fsg_lun_open(curlun, mod_data.file[i]);
-+ if (rc)
-+ goto out;
-+ } else if (!mod_data.removable) {
-+ ERROR(fsg, "no file given for LUN%d\n", i);
-+ rc = -EINVAL;
-+ goto out;
-+ }
-+ }
-+
-+ /* Find all the endpoints we will use */
-+ usb_ep_autoconfig_reset(gadget);
-+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
-+ if (!ep)
-+ goto autoconf_fail;
-+ ep->driver_data = fsg; // claim the endpoint
-+ fsg->bulk_in = ep;
-+
-+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
-+ if (!ep)
-+ goto autoconf_fail;
-+ ep->driver_data = fsg; // claim the endpoint
-+ fsg->bulk_out = ep;
-+
-+ if (transport_is_cbi()) {
-+ ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
-+ if (!ep)
-+ goto autoconf_fail;
-+ ep->driver_data = fsg; // claim the endpoint
-+ fsg->intr_in = ep;
-+ }
-+
-+ /* Fix up the descriptors */
-+ device_desc.idVendor = cpu_to_le16(mod_data.vendor);
-+ device_desc.idProduct = cpu_to_le16(mod_data.product);
-+ device_desc.bcdDevice = cpu_to_le16(mod_data.release);
-+
-+ i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
-+ fsg_intf_desc.bNumEndpoints = i;
-+ fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
-+ fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
-+ fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
-+
-+ if (gadget_is_dualspeed(gadget)) {
-+ fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
-+
-+ /* Assume endpoint addresses are the same for both speeds */
-+ fsg_hs_bulk_in_desc.bEndpointAddress =
-+ fsg_fs_bulk_in_desc.bEndpointAddress;
-+ fsg_hs_bulk_out_desc.bEndpointAddress =
-+ fsg_fs_bulk_out_desc.bEndpointAddress;
-+ fsg_hs_intr_in_desc.bEndpointAddress =
-+ fsg_fs_intr_in_desc.bEndpointAddress;
-+ }
-+
-+ if (gadget_is_superspeed(gadget)) {
-+ unsigned max_burst;
-+
-+ fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
-+
-+ /* Calculate bMaxBurst, we know packet size is 1024 */
-+ max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
-+
-+ /* Assume endpoint addresses are the same for both speeds */
-+ fsg_ss_bulk_in_desc.bEndpointAddress =
-+ fsg_fs_bulk_in_desc.bEndpointAddress;
-+ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
-+
-+ fsg_ss_bulk_out_desc.bEndpointAddress =
-+ fsg_fs_bulk_out_desc.bEndpointAddress;
-+ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
-+ }
-+
-+ if (gadget_is_otg(gadget))
-+ fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
-+
-+ rc = -ENOMEM;
-+
-+ /* Allocate the request and buffer for endpoint 0 */
-+ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
-+ if (!req)
-+ goto out;
-+ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
-+ if (!req->buf)
-+ goto out;
-+ req->complete = ep0_complete;
-+
-+ /* Allocate the data buffers */
-+ for (i = 0; i < fsg_num_buffers; ++i) {
-+ struct fsg_buffhd *bh = &fsg->buffhds[i];
-+
-+ /* Allocate for the bulk-in endpoint. We assume that
-+ * the buffer will also work with the bulk-out (and
-+ * interrupt-in) endpoint. */
-+ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
-+ if (!bh->buf)
-+ goto out;
-+ bh->next = bh + 1;
-+ }
-+ fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
-+
-+ /* This should reflect the actual gadget power source */
-+ usb_gadget_set_selfpowered(gadget);
-+
-+ snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
-+ "%s %s with %s",
-+ init_utsname()->sysname, init_utsname()->release,
-+ gadget->name);
-+
-+ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
-+ "file-storage-gadget");
-+ if (IS_ERR(fsg->thread_task)) {
-+ rc = PTR_ERR(fsg->thread_task);
-+ goto out;
-+ }
-+
-+ INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
-+ INFO(fsg, "NOTE: This driver is deprecated. "
-+ "Consider using g_mass_storage instead.\n");
-+ INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
-+
-+ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
-+ for (i = 0; i < fsg->nluns; ++i) {
-+ curlun = &fsg->luns[i];
-+ if (fsg_lun_is_open(curlun)) {
-+ p = NULL;
-+ if (pathbuf) {
-+ p = d_path(&curlun->filp->f_path,
-+ pathbuf, PATH_MAX);
-+ if (IS_ERR(p))
-+ p = NULL;
-+ }
-+ LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
-+ curlun->ro, curlun->nofua, (p ? p : "(error)"));
-+ }
-+ }
-+ kfree(pathbuf);
-+
-+ DBG(fsg, "transport=%s (x%02x)\n",
-+ mod_data.transport_name, mod_data.transport_type);
-+ DBG(fsg, "protocol=%s (x%02x)\n",
-+ mod_data.protocol_name, mod_data.protocol_type);
-+ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
-+ mod_data.vendor, mod_data.product, mod_data.release);
-+ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
-+ mod_data.removable, mod_data.can_stall,
-+ mod_data.cdrom, mod_data.buflen);
-+ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
-+
-+ set_bit(REGISTERED, &fsg->atomic_bitflags);
-+
-+ /* Tell the thread to start working */
-+ wake_up_process(fsg->thread_task);
-+ return 0;
-+
-+autoconf_fail:
-+ ERROR(fsg, "unable to autoconfigure all endpoints\n");
-+ rc = -ENOTSUPP;
-+
-+out:
-+ fsg->state = FSG_STATE_TERMINATED; // The thread is dead
-+ fsg_unbind(gadget);
-+ complete(&fsg->thread_notifier);
-+ return rc;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void fsg_suspend(struct usb_gadget *gadget)
-+{
-+ struct fsg_dev *fsg = get_gadget_data(gadget);
-+
-+ DBG(fsg, "suspend\n");
-+ set_bit(SUSPENDED, &fsg->atomic_bitflags);
-+}
-+
-+static void fsg_resume(struct usb_gadget *gadget)
-+{
-+ struct fsg_dev *fsg = get_gadget_data(gadget);
-+
-+ DBG(fsg, "resume\n");
-+ clear_bit(SUSPENDED, &fsg->atomic_bitflags);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static struct usb_gadget_driver fsg_driver = {
-+ .max_speed = USB_SPEED_SUPER,
-+ .function = (char *) fsg_string_product,
-+ .unbind = fsg_unbind,
-+ .disconnect = fsg_disconnect,
-+ .setup = fsg_setup,
-+ .suspend = fsg_suspend,
-+ .resume = fsg_resume,
-+
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ // .release = ...
-+ // .suspend = ...
-+ // .resume = ...
-+ },
-+};
-+
-+
-+static int __init fsg_alloc(void)
-+{
-+ struct fsg_dev *fsg;
-+
-+ fsg = kzalloc(sizeof *fsg +
-+ fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
-+
-+ if (!fsg)
-+ return -ENOMEM;
-+ spin_lock_init(&fsg->lock);
-+ init_rwsem(&fsg->filesem);
-+ kref_init(&fsg->ref);
-+ init_completion(&fsg->thread_notifier);
-+
-+ the_fsg = fsg;
-+ return 0;
-+}
-+
-+
-+static int __init fsg_init(void)
-+{
-+ int rc;
-+ struct fsg_dev *fsg;
-+
-+ rc = fsg_num_buffers_validate();
-+ if (rc != 0)
-+ return rc;
-+
-+ if ((rc = fsg_alloc()) != 0)
-+ return rc;
-+ fsg = the_fsg;
-+ if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
-+ kref_put(&fsg->ref, fsg_release);
-+ return rc;
-+}
-+module_init(fsg_init);
-+
-+
-+static void __exit fsg_cleanup(void)
-+{
-+ struct fsg_dev *fsg = the_fsg;
-+
-+ /* Unregister the driver iff the thread hasn't already done so */
-+ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
-+ usb_gadget_unregister_driver(&fsg_driver);
-+
-+ /* Wait for the thread to finish up */
-+ wait_for_completion(&fsg->thread_notifier);
-+
-+ kref_put(&fsg->ref, fsg_release);
-+}
-+module_exit(fsg_cleanup);
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/changes.txt linux-3.11.10/drivers/usb/host/dwc_common_port/changes.txt
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/changes.txt 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/changes.txt 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,174 @@
-+
-+dwc_read_reg32() and friends now take an additional parameter, a pointer to an
-+IO context struct. The IO context struct should live in an os-dependent struct
-+in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
-+named 'os_dep' embedded in the main device struct. So there these calls look
-+like this:
-+
-+ dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
-+
-+ dwc_write_reg32(&usb3_dev->os_dep.ioctx,
-+ &pcd->dev_global_regs->dcfg, 0);
-+
-+Note that for the existing Linux driver ports, it is not necessary to actually
-+define the 'ioctx' member in the os-dependent struct. Since Linux does not
-+require an IO context, its macros for dwc_read_reg32() and friends do not
-+use the context pointer, so it is optimized away by the compiler. But it is
-+necessary to add the pointer parameter to all of the call sites, to be ready
-+for any future ports (such as FreeBSD) which do require an IO context.
-+
-+
-+Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
-+take an additional parameter, a pointer to a memory context. Examples:
-+
-+ addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
-+
-+ dwc_free(&usb3_dev->os_dep.memctx, addr);
-+
-+Again, for the Linux ports, it is not necessary to actually define the memctx
-+member, but it is necessary to add the pointer parameter to all of the call
-+sites.
-+
-+
-+Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
-+
-+ virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
-+
-+ dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
-+
-+
-+Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
-+
-+ mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
-+
-+ dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
-+
-+
-+Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
-+
-+ lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
-+
-+ dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
-+
-+
-+Same for dwc_timer_alloc(). Example:
-+
-+ timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
-+ cb_func, cb_data);
-+
-+
-+Same for dwc_waitq_alloc(). Example:
-+
-+ waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
-+
-+
-+Same for dwc_thread_run(). Example:
-+
-+ thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
-+ "dwc_usb3_thd1", data);
-+
-+
-+Same for dwc_workq_alloc(). Example:
-+
-+ workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
-+
-+
-+Same for dwc_task_alloc(). Example:
-+
-+ task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
-+ cb_func, cb_data);
-+
-+
-+In addition to the context pointer additions, a few core functions have had
-+other changes made to their parameters:
-+
-+The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
-+has been changed from a uint64_t to a dwc_irqflags_t.
-+
-+dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
-+FreeBSD equivalent of that function requires it.
-+
-+And, in addition to the context pointer, dwc_task_alloc() also adds a
-+'char *name' parameter, to be consistent with dwc_thread_run() and
-+dwc_workq_alloc(), and because the FreeBSD equivalent of that function
-+requires a unique name.
-+
-+
-+Here is a complete list of the core functions that now take a pointer to a
-+context as their first parameter:
-+
-+ dwc_read_reg32
-+ dwc_read_reg64
-+ dwc_write_reg32
-+ dwc_write_reg64
-+ dwc_modify_reg32
-+ dwc_modify_reg64
-+ dwc_alloc
-+ dwc_alloc_atomic
-+ dwc_strdup
-+ dwc_free
-+ dwc_dma_alloc
-+ dwc_dma_free
-+ dwc_mutex_alloc
-+ dwc_mutex_free
-+ dwc_spinlock_alloc
-+ dwc_spinlock_free
-+ dwc_timer_alloc
-+ dwc_waitq_alloc
-+ dwc_thread_run
-+ dwc_workq_alloc
-+ dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
-+
-+And here are the core functions that have other changes to their parameters:
-+
-+ dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
-+ dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
-+ dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
-+
-+
-+
-+The changes to the core functions also require some of the other library
-+functions to change:
-+
-+ dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
-+ (for memory allocation) as the 1st param and a 'void *mtxctx'
-+ (for mutex allocation) as the 2nd param.
-+
-+ dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
-+ dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
-+ 'void *memctx' as the 1st param.
-+
-+ dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
-+ 'void *memctx' as the 1st param.
-+
-+ dwc_modpow() now takes a 'void *memctx' as the 1st param.
-+
-+ dwc_alloc_notification_manager() now takes a 'void *memctx' as the
-+ 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
-+ param, and also now returns an integer value that is non-zero if
-+ allocation of its data structures or work queue fails.
-+
-+ dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
-+
-+ dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
-+ param, and also now returns an integer value that is non-zero if
-+ allocation of its data structures fails.
-+
-+
-+
-+Other miscellaneous changes:
-+
-+The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
-+DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
-+
-+The following #define's have been added to allow selectively compiling library
-+features:
-+
-+ DWC_CCLIB
-+ DWC_CRYPTOLIB
-+ DWC_NOTIFYLIB
-+ DWC_UTFLIB
-+
-+A DWC_LIBMODULE #define has also been added. If this is not defined, then the
-+module code in dwc_common_linux.c is not compiled in. This allows linking the
-+library code directly into a driver module, instead of as a standalone module.
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/doc/doxygen.cfg linux-3.11.10/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/doc/doxygen.cfg 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/doc/doxygen.cfg 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,270 @@
-+# Doxyfile 1.4.5
-+
-+#---------------------------------------------------------------------------
-+# Project related configuration options
-+#---------------------------------------------------------------------------
-+PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
-+PROJECT_NUMBER =
-+OUTPUT_DIRECTORY = doc
-+CREATE_SUBDIRS = NO
-+OUTPUT_LANGUAGE = English
-+BRIEF_MEMBER_DESC = YES
-+REPEAT_BRIEF = YES
-+ABBREVIATE_BRIEF = "The $name class" \
-+ "The $name widget" \
-+ "The $name file" \
-+ is \
-+ provides \
-+ specifies \
-+ contains \
-+ represents \
-+ a \
-+ an \
-+ the
-+ALWAYS_DETAILED_SEC = YES
-+INLINE_INHERITED_MEMB = NO
-+FULL_PATH_NAMES = NO
-+STRIP_FROM_PATH = ..
-+STRIP_FROM_INC_PATH =
-+SHORT_NAMES = NO
-+JAVADOC_AUTOBRIEF = YES
-+MULTILINE_CPP_IS_BRIEF = NO
-+DETAILS_AT_TOP = YES
-+INHERIT_DOCS = YES
-+SEPARATE_MEMBER_PAGES = NO
-+TAB_SIZE = 8
-+ALIASES =
-+OPTIMIZE_OUTPUT_FOR_C = YES
-+OPTIMIZE_OUTPUT_JAVA = NO
-+BUILTIN_STL_SUPPORT = NO
-+DISTRIBUTE_GROUP_DOC = NO
-+SUBGROUPING = NO
-+#---------------------------------------------------------------------------
-+# Build related configuration options
-+#---------------------------------------------------------------------------
-+EXTRACT_ALL = NO
-+EXTRACT_PRIVATE = NO
-+EXTRACT_STATIC = YES
-+EXTRACT_LOCAL_CLASSES = NO
-+EXTRACT_LOCAL_METHODS = NO
-+HIDE_UNDOC_MEMBERS = NO
-+HIDE_UNDOC_CLASSES = NO
-+HIDE_FRIEND_COMPOUNDS = NO
-+HIDE_IN_BODY_DOCS = NO
-+INTERNAL_DOCS = NO
-+CASE_SENSE_NAMES = YES
-+HIDE_SCOPE_NAMES = NO
-+SHOW_INCLUDE_FILES = NO
-+INLINE_INFO = YES
-+SORT_MEMBER_DOCS = NO
-+SORT_BRIEF_DOCS = NO
-+SORT_BY_SCOPE_NAME = NO
-+GENERATE_TODOLIST = YES
-+GENERATE_TESTLIST = YES
-+GENERATE_BUGLIST = YES
-+GENERATE_DEPRECATEDLIST= YES
-+ENABLED_SECTIONS =
-+MAX_INITIALIZER_LINES = 30
-+SHOW_USED_FILES = YES
-+SHOW_DIRECTORIES = YES
-+FILE_VERSION_FILTER =
-+#---------------------------------------------------------------------------
-+# configuration options related to warning and progress messages
-+#---------------------------------------------------------------------------
-+QUIET = YES
-+WARNINGS = YES
-+WARN_IF_UNDOCUMENTED = NO
-+WARN_IF_DOC_ERROR = YES
-+WARN_NO_PARAMDOC = YES
-+WARN_FORMAT = "$file:$line: $text"
-+WARN_LOGFILE =
-+#---------------------------------------------------------------------------
-+# configuration options related to the input files
-+#---------------------------------------------------------------------------
-+INPUT = .
-+FILE_PATTERNS = *.c \
-+ *.cc \
-+ *.cxx \
-+ *.cpp \
-+ *.c++ \
-+ *.d \
-+ *.java \
-+ *.ii \
-+ *.ixx \
-+ *.ipp \
-+ *.i++ \
-+ *.inl \
-+ *.h \
-+ *.hh \
-+ *.hxx \
-+ *.hpp \
-+ *.h++ \
-+ *.idl \
-+ *.odl \
-+ *.cs \
-+ *.php \
-+ *.php3 \
-+ *.inc \
-+ *.m \
-+ *.mm \
-+ *.dox \
-+ *.py \
-+ *.C \
-+ *.CC \
-+ *.C++ \
-+ *.II \
-+ *.I++ \
-+ *.H \
-+ *.HH \
-+ *.H++ \
-+ *.CS \
-+ *.PHP \
-+ *.PHP3 \
-+ *.M \
-+ *.MM \
-+ *.PY
-+RECURSIVE = NO
-+EXCLUDE =
-+EXCLUDE_SYMLINKS = NO
-+EXCLUDE_PATTERNS =
-+EXAMPLE_PATH =
-+EXAMPLE_PATTERNS = *
-+EXAMPLE_RECURSIVE = NO
-+IMAGE_PATH =
-+INPUT_FILTER =
-+FILTER_PATTERNS =
-+FILTER_SOURCE_FILES = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to source browsing
-+#---------------------------------------------------------------------------
-+SOURCE_BROWSER = NO
-+INLINE_SOURCES = NO
-+STRIP_CODE_COMMENTS = YES
-+REFERENCED_BY_RELATION = YES
-+REFERENCES_RELATION = YES
-+USE_HTAGS = NO
-+VERBATIM_HEADERS = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the alphabetical class index
-+#---------------------------------------------------------------------------
-+ALPHABETICAL_INDEX = NO
-+COLS_IN_ALPHA_INDEX = 5
-+IGNORE_PREFIX =
-+#---------------------------------------------------------------------------
-+# configuration options related to the HTML output
-+#---------------------------------------------------------------------------
-+GENERATE_HTML = YES
-+HTML_OUTPUT = html
-+HTML_FILE_EXTENSION = .html
-+HTML_HEADER =
-+HTML_FOOTER =
-+HTML_STYLESHEET =
-+HTML_ALIGN_MEMBERS = YES
-+GENERATE_HTMLHELP = NO
-+CHM_FILE =
-+HHC_LOCATION =
-+GENERATE_CHI = NO
-+BINARY_TOC = NO
-+TOC_EXPAND = NO
-+DISABLE_INDEX = NO
-+ENUM_VALUES_PER_LINE = 4
-+GENERATE_TREEVIEW = YES
-+TREEVIEW_WIDTH = 250
-+#---------------------------------------------------------------------------
-+# configuration options related to the LaTeX output
-+#---------------------------------------------------------------------------
-+GENERATE_LATEX = NO
-+LATEX_OUTPUT = latex
-+LATEX_CMD_NAME = latex
-+MAKEINDEX_CMD_NAME = makeindex
-+COMPACT_LATEX = NO
-+PAPER_TYPE = a4wide
-+EXTRA_PACKAGES =
-+LATEX_HEADER =
-+PDF_HYPERLINKS = NO
-+USE_PDFLATEX = NO
-+LATEX_BATCHMODE = NO
-+LATEX_HIDE_INDICES = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the RTF output
-+#---------------------------------------------------------------------------
-+GENERATE_RTF = NO
-+RTF_OUTPUT = rtf
-+COMPACT_RTF = NO
-+RTF_HYPERLINKS = NO
-+RTF_STYLESHEET_FILE =
-+RTF_EXTENSIONS_FILE =
-+#---------------------------------------------------------------------------
-+# configuration options related to the man page output
-+#---------------------------------------------------------------------------
-+GENERATE_MAN = NO
-+MAN_OUTPUT = man
-+MAN_EXTENSION = .3
-+MAN_LINKS = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the XML output
-+#---------------------------------------------------------------------------
-+GENERATE_XML = NO
-+XML_OUTPUT = xml
-+XML_SCHEMA =
-+XML_DTD =
-+XML_PROGRAMLISTING = YES
-+#---------------------------------------------------------------------------
-+# configuration options for the AutoGen Definitions output
-+#---------------------------------------------------------------------------
-+GENERATE_AUTOGEN_DEF = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the Perl module output
-+#---------------------------------------------------------------------------
-+GENERATE_PERLMOD = NO
-+PERLMOD_LATEX = NO
-+PERLMOD_PRETTY = YES
-+PERLMOD_MAKEVAR_PREFIX =
-+#---------------------------------------------------------------------------
-+# Configuration options related to the preprocessor
-+#---------------------------------------------------------------------------
-+ENABLE_PREPROCESSING = YES
-+MACRO_EXPANSION = NO
-+EXPAND_ONLY_PREDEF = NO
-+SEARCH_INCLUDES = YES
-+INCLUDE_PATH =
-+INCLUDE_FILE_PATTERNS =
-+PREDEFINED = DEBUG DEBUG_MEMORY
-+EXPAND_AS_DEFINED =
-+SKIP_FUNCTION_MACROS = YES
-+#---------------------------------------------------------------------------
-+# Configuration::additions related to external references
-+#---------------------------------------------------------------------------
-+TAGFILES =
-+GENERATE_TAGFILE =
-+ALLEXTERNALS = NO
-+EXTERNAL_GROUPS = YES
-+PERL_PATH = /usr/bin/perl
-+#---------------------------------------------------------------------------
-+# Configuration options related to the dot tool
-+#---------------------------------------------------------------------------
-+CLASS_DIAGRAMS = YES
-+HIDE_UNDOC_RELATIONS = YES
-+HAVE_DOT = NO
-+CLASS_GRAPH = YES
-+COLLABORATION_GRAPH = YES
-+GROUP_GRAPHS = YES
-+UML_LOOK = NO
-+TEMPLATE_RELATIONS = NO
-+INCLUDE_GRAPH = NO
-+INCLUDED_BY_GRAPH = YES
-+CALL_GRAPH = NO
-+GRAPHICAL_HIERARCHY = YES
-+DIRECTORY_GRAPH = YES
-+DOT_IMAGE_FORMAT = png
-+DOT_PATH =
-+DOTFILE_DIRS =
-+MAX_DOT_GRAPH_DEPTH = 1000
-+DOT_TRANSPARENT = NO
-+DOT_MULTI_TARGETS = NO
-+GENERATE_LEGEND = YES
-+DOT_CLEANUP = YES
-+#---------------------------------------------------------------------------
-+# Configuration::additions related to the search engine
-+#---------------------------------------------------------------------------
-+SEARCHENGINE = NO
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_cc.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_cc.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_cc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_cc.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,532 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
-+ * $Revision: #4 $
-+ * $Date: 2010/11/04 $
-+ * $Change: 1621692 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+#ifdef DWC_CCLIB
-+
-+#include "dwc_cc.h"
-+
-+typedef struct dwc_cc
-+{
-+ uint32_t uid;
-+ uint8_t chid[16];
-+ uint8_t cdid[16];
-+ uint8_t ck[16];
-+ uint8_t *name;
-+ uint8_t length;
-+ DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
-+} dwc_cc_t;
-+
-+DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
-+
-+/** The main structure for CC management. */
-+struct dwc_cc_if
-+{
-+ dwc_mutex_t *mutex;
-+ char *filename;
-+
-+ unsigned is_host:1;
-+
-+ dwc_notifier_t *notifier;
-+
-+ struct context_list list;
-+};
-+
-+#ifdef DEBUG
-+static inline void dump_bytes(char *name, uint8_t *bytes, int len)
-+{
-+ int i;
-+ DWC_PRINTF("%s: ", name);
-+ for (i=0; i<len; i++) {
-+ DWC_PRINTF("%02x ", bytes[i]);
-+ }
-+ DWC_PRINTF("\n");
-+}
-+#else
-+#define dump_bytes(x...)
-+#endif
-+
-+static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
-+{
-+ dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
-+ if (!cc) {
-+ return NULL;
-+ }
-+ DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
-+
-+ if (name) {
-+ cc->length = length;
-+ cc->name = dwc_alloc(mem_ctx, length);
-+ if (!cc->name) {
-+ dwc_free(mem_ctx, cc);
-+ return NULL;
-+ }
-+
-+ DWC_MEMCPY(cc->name, name, length);
-+ }
-+
-+ return cc;
-+}
-+
-+static void free_cc(void *mem_ctx, dwc_cc_t *cc)
-+{
-+ if (cc->name) {
-+ dwc_free(mem_ctx, cc->name);
-+ }
-+ dwc_free(mem_ctx, cc);
-+}
-+
-+static uint32_t next_uid(dwc_cc_if_t *cc_if)
-+{
-+ uint32_t uid = 0;
-+ dwc_cc_t *cc;
-+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
-+ if (cc->uid > uid) {
-+ uid = cc->uid;
-+ }
-+ }
-+
-+ if (uid == 0) {
-+ uid = 255;
-+ }
-+
-+ return uid + 1;
-+}
-+
-+static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
-+{
-+ dwc_cc_t *cc;
-+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
-+ if (cc->uid == uid) {
-+ return cc;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
-+{
-+ unsigned int size = 0;
-+ dwc_cc_t *cc;
-+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
-+ size += (48 + 1);
-+ if (cc->name) {
-+ size += cc->length;
-+ }
-+ }
-+ return size;
-+}
-+
-+static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
-+{
-+ uint32_t uid = 0;
-+ dwc_cc_t *cc;
-+
-+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
-+ if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
-+ uid = cc->uid;
-+ break;
-+ }
-+ }
-+ return uid;
-+}
-+static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
-+{
-+ uint32_t uid = 0;
-+ dwc_cc_t *cc;
-+
-+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
-+ if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
-+ uid = cc->uid;
-+ break;
-+ }
-+ }
-+ return uid;
-+}
-+
-+/* Internal cc_add */
-+static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
-+ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
-+{
-+ dwc_cc_t *cc;
-+ uint32_t uid;
-+
-+ if (cc_if->is_host) {
-+ uid = cc_match_cdid(cc_if, cdid);
-+ }
-+ else {
-+ uid = cc_match_chid(cc_if, chid);
-+ }
-+
-+ if (uid) {
-+ DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
-+ cc = cc_find(cc_if, uid);
-+ }
-+ else {
-+ cc = alloc_cc(mem_ctx, name, length);
-+ cc->uid = next_uid(cc_if);
-+ DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
-+ }
-+
-+ DWC_MEMCPY(&(cc->chid[0]), chid, 16);
-+ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
-+ DWC_MEMCPY(&(cc->ck[0]), ck, 16);
-+
-+ DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
-+ dump_bytes("CHID", cc->chid, 16);
-+ dump_bytes("CDID", cc->cdid, 16);
-+ dump_bytes("CK", cc->ck, 16);
-+ return cc->uid;
-+}
-+
-+/* Internal cc_clear */
-+static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
-+{
-+ while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
-+ dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
-+ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
-+ free_cc(mem_ctx, cc);
-+ }
-+}
-+
-+dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
-+ dwc_notifier_t *notifier, unsigned is_host)
-+{
-+ dwc_cc_if_t *cc_if = NULL;
-+
-+ /* Allocate a common_cc_if structure */
-+ cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
-+
-+ if (!cc_if)
-+ return NULL;
-+
-+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
-+ DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
-+#else
-+ cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
-+#endif
-+ if (!cc_if->mutex) {
-+ dwc_free(mem_ctx, cc_if);
-+ return NULL;
-+ }
-+
-+ DWC_CIRCLEQ_INIT(&cc_if->list);
-+ cc_if->is_host = is_host;
-+ cc_if->notifier = notifier;
-+ return cc_if;
-+}
-+
-+void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
-+{
-+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
-+ DWC_MUTEX_FREE(cc_if->mutex);
-+#else
-+ dwc_mutex_free(mtx_ctx, cc_if->mutex);
-+#endif
-+ cc_clear(mem_ctx, cc_if);
-+ dwc_free(mem_ctx, cc_if);
-+}
-+
-+static void cc_changed(dwc_cc_if_t *cc_if)
-+{
-+ if (cc_if->notifier) {
-+ dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
-+ }
-+}
-+
-+void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
-+{
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc_clear(mem_ctx, cc_if);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ cc_changed(cc_if);
-+}
-+
-+int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
-+ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
-+{
-+ uint32_t uid;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ cc_changed(cc_if);
-+
-+ return uid;
-+}
-+
-+void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
-+ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
-+{
-+ dwc_cc_t* cc;
-+
-+ DWC_DEBUGC("Change connection context %d", id);
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc = cc_find(cc_if, id);
-+ if (!cc) {
-+ DWC_ERROR("Uid %d not found in cc list\n", id);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return;
-+ }
-+
-+ if (chid) {
-+ DWC_MEMCPY(&(cc->chid[0]), chid, 16);
-+ }
-+ if (cdid) {
-+ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
-+ }
-+ if (ck) {
-+ DWC_MEMCPY(&(cc->ck[0]), ck, 16);
-+ }
-+
-+ if (name) {
-+ if (cc->name) {
-+ dwc_free(mem_ctx, cc->name);
-+ }
-+ cc->name = dwc_alloc(mem_ctx, length);
-+ if (!cc->name) {
-+ DWC_ERROR("Out of memory in dwc_cc_change()\n");
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return;
-+ }
-+ cc->length = length;
-+ DWC_MEMCPY(cc->name, name, length);
-+ }
-+
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ cc_changed(cc_if);
-+
-+ DWC_DEBUGC("Changed connection context id=%d\n", id);
-+ dump_bytes("New CHID", cc->chid, 16);
-+ dump_bytes("New CDID", cc->cdid, 16);
-+ dump_bytes("New CK", cc->ck, 16);
-+}
-+
-+void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
-+{
-+ dwc_cc_t *cc;
-+
-+ DWC_DEBUGC("Removing connection context %d", id);
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc = cc_find(cc_if, id);
-+ if (!cc) {
-+ DWC_ERROR("Uid %d not found in cc list\n", id);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return;
-+ }
-+
-+ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ free_cc(mem_ctx, cc);
-+
-+ cc_changed(cc_if);
-+}
-+
-+uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
-+{
-+ uint8_t *buf, *x;
-+ uint8_t zero = 0;
-+ dwc_cc_t *cc;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ *length = cc_data_size(cc_if);
-+ if (!(*length)) {
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return NULL;
-+ }
-+
-+ DWC_DEBUGC("Creating data for saving (length=%d)", *length);
-+
-+ buf = dwc_alloc(mem_ctx, *length);
-+ if (!buf) {
-+ *length = 0;
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return NULL;
-+ }
-+
-+ x = buf;
-+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
-+ DWC_MEMCPY(x, cc->chid, 16);
-+ x += 16;
-+ DWC_MEMCPY(x, cc->cdid, 16);
-+ x += 16;
-+ DWC_MEMCPY(x, cc->ck, 16);
-+ x += 16;
-+ if (cc->name) {
-+ DWC_MEMCPY(x, &cc->length, 1);
-+ x += 1;
-+ DWC_MEMCPY(x, cc->name, cc->length);
-+ x += cc->length;
-+ }
-+ else {
-+ DWC_MEMCPY(x, &zero, 1);
-+ x += 1;
-+ }
-+ }
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ return buf;
-+}
-+
-+void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
-+{
-+ uint8_t name_length;
-+ uint8_t *name;
-+ uint8_t *chid;
-+ uint8_t *cdid;
-+ uint8_t *ck;
-+ uint32_t i = 0;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc_clear(mem_ctx, cc_if);
-+
-+ while (i < length) {
-+ chid = &data[i];
-+ i += 16;
-+ cdid = &data[i];
-+ i += 16;
-+ ck = &data[i];
-+ i += 16;
-+
-+ name_length = data[i];
-+ i ++;
-+
-+ if (name_length) {
-+ name = &data[i];
-+ i += name_length;
-+ }
-+ else {
-+ name = NULL;
-+ }
-+
-+ /* check to see if we haven't overflown the buffer */
-+ if (i > length) {
-+ DWC_ERROR("Data format error while attempting to load CCs "
-+ "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
-+ break;
-+ }
-+
-+ cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
-+ }
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ cc_changed(cc_if);
-+}
-+
-+uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
-+{
-+ uint32_t uid = 0;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ uid = cc_match_chid(cc_if, chid);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return uid;
-+}
-+uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
-+{
-+ uint32_t uid = 0;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ uid = cc_match_cdid(cc_if, cdid);
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+ return uid;
-+}
-+
-+uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
-+{
-+ uint8_t *ck = NULL;
-+ dwc_cc_t *cc;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc = cc_find(cc_if, id);
-+ if (cc) {
-+ ck = cc->ck;
-+ }
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ return ck;
-+
-+}
-+
-+uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
-+{
-+ uint8_t *retval = NULL;
-+ dwc_cc_t *cc;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc = cc_find(cc_if, id);
-+ if (cc) {
-+ retval = cc->chid;
-+ }
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ return retval;
-+}
-+
-+uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
-+{
-+ uint8_t *retval = NULL;
-+ dwc_cc_t *cc;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ cc = cc_find(cc_if, id);
-+ if (cc) {
-+ retval = cc->cdid;
-+ }
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ return retval;
-+}
-+
-+uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
-+{
-+ uint8_t *retval = NULL;
-+ dwc_cc_t *cc;
-+
-+ DWC_MUTEX_LOCK(cc_if->mutex);
-+ *length = 0;
-+ cc = cc_find(cc_if, id);
-+ if (cc) {
-+ *length = cc->length;
-+ retval = cc->name;
-+ }
-+ DWC_MUTEX_UNLOCK(cc_if->mutex);
-+
-+ return retval;
-+}
-+
-+#endif /* DWC_CCLIB */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_cc.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_cc.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_cc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_cc.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,224 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
-+ * $Revision: #4 $
-+ * $Date: 2010/09/28 $
-+ * $Change: 1596182 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+#ifndef _DWC_CC_H_
-+#define _DWC_CC_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** @file
-+ *
-+ * This file defines the Context Context library.
-+ *
-+ * The main data structure is dwc_cc_if_t which is returned by either the
-+ * dwc_cc_if_alloc function or returned by the module to the user via a provided
-+ * function. The data structure is opaque and should only be manipulated via the
-+ * functions provied in this API.
-+ *
-+ * It manages a list of connection contexts and operations can be performed to
-+ * add, remove, query, search, and change, those contexts. Additionally,
-+ * a dwc_notifier_t object can be requested from the manager so that
-+ * the user can be notified whenever the context list has changed.
-+ */
-+
-+#include "dwc_os.h"
-+#include "dwc_list.h"
-+#include "dwc_notifier.h"
-+
-+
-+/* Notifications */
-+#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
-+
-+struct dwc_cc_if;
-+typedef struct dwc_cc_if dwc_cc_if_t;
-+
-+
-+/** @name Connection Context Operations */
-+/** @{ */
-+
-+/** This function allocates memory for a dwc_cc_if_t structure, initializes
-+ * fields to default values, and returns a pointer to the structure or NULL on
-+ * error. */
-+extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
-+ dwc_notifier_t *notifier, unsigned is_host);
-+
-+/** Frees the memory for the specified CC structure allocated from
-+ * dwc_cc_if_alloc(). */
-+extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
-+
-+/** Removes all contexts from the connection context list */
-+extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
-+
-+/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
-+ * If a CHID already exists, the CK and name are overwritten. Statistics are
-+ * not overwritten.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param chid A pointer to the 16-byte CHID. This value will be copied.
-+ * @param ck A pointer to the 16-byte CK. This value will be copied.
-+ * @param cdid A pointer to the 16-byte CDID. This value will be copied.
-+ * @param name An optional host friendly name as defined in the association model
-+ * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
-+ * @param length The length othe unicode string.
-+ * @return A unique identifier used to refer to this context that is valid for
-+ * as long as this context is still in the list. */
-+extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
-+ uint8_t *cdid, uint8_t *ck, uint8_t *name,
-+ uint8_t length);
-+
-+/** Changes the CHID, CK, CDID, or Name values of a connection context in the
-+ * list, preserving any accumulated statistics. This would typically be called
-+ * if the host decideds to change the context with a SET_CONNECTION request.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param id The identifier of the connection context.
-+ * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
-+ * indicates no change.
-+ * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
-+ * indicates no change.
-+ * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
-+ * indicates no change.
-+ * @param name Host friendly name UTF16-LE. NULL indicates no change.
-+ * @param length Length of name. */
-+extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
-+ uint8_t *chid, uint8_t *cdid, uint8_t *ck,
-+ uint8_t *name, uint8_t length);
-+
-+/** Remove the specified connection context.
-+ * @param cc_if The cc_if structure.
-+ * @param id The identifier of the connection context to remove. */
-+extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
-+
-+/** Get a binary block of data for the connection context list and attributes.
-+ * This data can be used by the OS specific driver to save the connection
-+ * context list into non-volatile memory.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param length Return the length of the data buffer.
-+ * @return A pointer to the data buffer. The memory for this buffer should be
-+ * freed with DWC_FREE() after use. */
-+extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
-+ unsigned int *length);
-+
-+/** Restore the connection context list from the binary data that was previously
-+ * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
-+ * driver to load a connection context list from non-volatile memory.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param data The data bytes as returned from dwc_cc_data_for_save.
-+ * @param length The length of the data. */
-+extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
-+ uint8_t *data, unsigned int length);
-+
-+/** Find the connection context from the specified CHID.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param chid A pointer to the CHID data.
-+ * @return A non-zero identifier of the connection context if the CHID matches.
-+ * Otherwise returns 0. */
-+extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
-+
-+/** Find the connection context from the specified CDID.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param cdid A pointer to the CDID data.
-+ * @return A non-zero identifier of the connection context if the CHID matches.
-+ * Otherwise returns 0. */
-+extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
-+
-+/** Retrieve the CK from the specified connection context.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param id The identifier of the connection context.
-+ * @return A pointer to the CK data. The memory does not need to be freed. */
-+extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
-+
-+/** Retrieve the CHID from the specified connection context.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param id The identifier of the connection context.
-+ * @return A pointer to the CHID data. The memory does not need to be freed. */
-+extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
-+
-+/** Retrieve the CDID from the specified connection context.
-+ *
-+ * @param cc_if The cc_if structure.
-+ * @param id The identifier of the connection context.
-+ * @return A pointer to the CDID data. The memory does not need to be freed. */
-+extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
-+
-+extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
-+
-+/** Checks a buffer for non-zero.
-+ * @param id A pointer to a 16 byte buffer.
-+ * @return true if the 16 byte value is non-zero. */
-+static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
-+ int i;
-+ for (i=0; i<16; i++) {
-+ if (id[i]) return 1;
-+ }
-+ return 0;
-+}
-+
-+/** Checks a buffer for zero.
-+ * @param id A pointer to a 16 byte buffer.
-+ * @return true if the 16 byte value is zero. */
-+static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
-+ return !dwc_assoc_is_not_zero_id(id);
-+}
-+
-+/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
-+ * buffer. */
-+static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
-+ char *ptr = buffer;
-+ int i;
-+ for (i=0; i<16; i++) {
-+ ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
-+ if (i < 15) {
-+ ptr += DWC_SPRINTF(ptr, " ");
-+ }
-+ }
-+ return ptr - buffer;
-+}
-+
-+/** @} */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _DWC_CC_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1308 @@
-+#include "dwc_os.h"
-+#include "dwc_list.h"
-+
-+#ifdef DWC_CCLIB
-+# include "dwc_cc.h"
-+#endif
-+
-+#ifdef DWC_CRYPTOLIB
-+# include "dwc_modpow.h"
-+# include "dwc_dh.h"
-+# include "dwc_crypto.h"
-+#endif
-+
-+#ifdef DWC_NOTIFYLIB
-+# include "dwc_notifier.h"
-+#endif
-+
-+/* OS-Level Implementations */
-+
-+/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
-+
-+
-+/* MISC */
-+
-+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
-+{
-+ return memset(dest, byte, size);
-+}
-+
-+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
-+{
-+ return memcpy(dest, src, size);
-+}
-+
-+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
-+{
-+ bcopy(src, dest, size);
-+ return dest;
-+}
-+
-+int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
-+{
-+ return memcmp(m1, m2, size);
-+}
-+
-+int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
-+{
-+ return strncmp(s1, s2, size);
-+}
-+
-+int DWC_STRCMP(void *s1, void *s2)
-+{
-+ return strcmp(s1, s2);
-+}
-+
-+int DWC_STRLEN(char const *str)
-+{
-+ return strlen(str);
-+}
-+
-+char *DWC_STRCPY(char *to, char const *from)
-+{
-+ return strcpy(to, from);
-+}
-+
-+char *DWC_STRDUP(char const *str)
-+{
-+ int len = DWC_STRLEN(str) + 1;
-+ char *new = DWC_ALLOC_ATOMIC(len);
-+
-+ if (!new) {
-+ return NULL;
-+ }
-+
-+ DWC_MEMCPY(new, str, len);
-+ return new;
-+}
-+
-+int DWC_ATOI(char *str, int32_t *value)
-+{
-+ char *end = NULL;
-+
-+ *value = strtol(str, &end, 0);
-+ if (*end == '\0') {
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+int DWC_ATOUI(char *str, uint32_t *value)
-+{
-+ char *end = NULL;
-+
-+ *value = strtoul(str, &end, 0);
-+ if (*end == '\0') {
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+
-+#ifdef DWC_UTFLIB
-+/* From usbstring.c */
-+
-+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
-+{
-+ int count = 0;
-+ u8 c;
-+ u16 uchar;
-+
-+ /* this insists on correct encodings, though not minimal ones.
-+ * BUT it currently rejects legit 4-byte UTF-8 code points,
-+ * which need surrogate pairs. (Unicode 3.1 can use them.)
-+ */
-+ while (len != 0 && (c = (u8) *s++) != 0) {
-+ if (unlikely(c & 0x80)) {
-+ // 2-byte sequence:
-+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-+ if ((c & 0xe0) == 0xc0) {
-+ uchar = (c & 0x1f) << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ // 3-byte sequence (most CJKV characters):
-+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-+ } else if ((c & 0xf0) == 0xe0) {
-+ uchar = (c & 0x0f) << 12;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ /* no bogus surrogates */
-+ if (0xd800 <= uchar && uchar <= 0xdfff)
-+ goto fail;
-+
-+ // 4-byte sequence (surrogate pairs, currently rare):
-+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-+ // (uuuuu = wwww + 1)
-+ // FIXME accept the surrogate code points (only)
-+ } else
-+ goto fail;
-+ } else
-+ uchar = c;
-+ put_unaligned (cpu_to_le16 (uchar), cp++);
-+ count++;
-+ len--;
-+ }
-+ return count;
-+fail:
-+ return -1;
-+}
-+
-+#endif /* DWC_UTFLIB */
-+
-+
-+/* dwc_debug.h */
-+
-+dwc_bool_t DWC_IN_IRQ(void)
-+{
-+// return in_irq();
-+ return 0;
-+}
-+
-+dwc_bool_t DWC_IN_BH(void)
-+{
-+// return in_softirq();
-+ return 0;
-+}
-+
-+void DWC_VPRINTF(char *format, va_list args)
-+{
-+ vprintf(format, args);
-+}
-+
-+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
-+{
-+ return vsnprintf(str, size, format, args);
-+}
-+
-+void DWC_PRINTF(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+int DWC_SPRINTF(char *buffer, char *format, ...)
-+{
-+ int retval;
-+ va_list args;
-+
-+ va_start(args, format);
-+ retval = vsprintf(buffer, format, args);
-+ va_end(args);
-+ return retval;
-+}
-+
-+int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
-+{
-+ int retval;
-+ va_list args;
-+
-+ va_start(args, format);
-+ retval = vsnprintf(buffer, size, format, args);
-+ va_end(args);
-+ return retval;
-+}
-+
-+void __DWC_WARN(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+void __DWC_ERROR(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+void DWC_EXCEPTION(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+// BUG_ON(1); ???
-+}
-+
-+#ifdef DEBUG
-+void __DWC_DEBUG(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+#endif
-+
-+
-+/* dwc_mem.h */
-+
-+#if 0
-+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
-+ uint32_t align,
-+ uint32_t alloc)
-+{
-+ struct dma_pool *pool = dma_pool_create("Pool", NULL,
-+ size, align, alloc);
-+ return (dwc_pool_t *)pool;
-+}
-+
-+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
-+{
-+ dma_pool_destroy((struct dma_pool *)pool);
-+}
-+
-+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
-+{
-+// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
-+ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
-+}
-+
-+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
-+{
-+ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
-+ memset(..);
-+}
-+
-+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
-+{
-+ dma_pool_free(pool, vaddr, daddr);
-+}
-+#endif
-+
-+static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-+{
-+ if (error)
-+ return;
-+ *(bus_addr_t *)arg = segs[0].ds_addr;
-+}
-+
-+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
-+{
-+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
-+ int error;
-+
-+ error = bus_dma_tag_create(
-+#if __FreeBSD_version >= 700000
-+ bus_get_dma_tag(dma->dev), /* parent */
-+#else
-+ NULL, /* parent */
-+#endif
-+ 4, 0, /* alignment, bounds */
-+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
-+ BUS_SPACE_MAXADDR, /* highaddr */
-+ NULL, NULL, /* filter, filterarg */
-+ size, /* maxsize */
-+ 1, /* nsegments */
-+ size, /* maxsegsize */
-+ 0, /* flags */
-+ NULL, /* lockfunc */
-+ NULL, /* lockarg */
-+ &dma->dma_tag);
-+ if (error) {
-+ device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
-+ __func__, error);
-+ goto fail_0;
-+ }
-+
-+ error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
-+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
-+ if (error) {
-+ device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
-+ __func__, (uintmax_t)size, error);
-+ goto fail_1;
-+ }
-+
-+ dma->dma_paddr = 0;
-+ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
-+ dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
-+ if (error || dma->dma_paddr == 0) {
-+ device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
-+ __func__, error);
-+ goto fail_2;
-+ }
-+
-+ *dma_addr = dma->dma_paddr;
-+ return dma->dma_vaddr;
-+
-+fail_2:
-+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
-+fail_1:
-+ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
-+ bus_dma_tag_destroy(dma->dma_tag);
-+fail_0:
-+ dma->dma_map = NULL;
-+ dma->dma_tag = NULL;
-+
-+ return NULL;
-+}
-+
-+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
-+{
-+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
-+
-+ if (dma->dma_tag == NULL)
-+ return;
-+ if (dma->dma_map != NULL) {
-+ bus_dmamap_sync(dma->dma_tag, dma->dma_map,
-+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
-+ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
-+ dma->dma_map = NULL;
-+ }
-+
-+ bus_dma_tag_destroy(dma->dma_tag);
-+ dma->dma_tag = NULL;
-+}
-+
-+void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
-+{
-+ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
-+}
-+
-+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
-+{
-+ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
-+}
-+
-+void __DWC_FREE(void *mem_ctx, void *addr)
-+{
-+ free(addr, M_DEVBUF);
-+}
-+
-+
-+#ifdef DWC_CRYPTOLIB
-+/* dwc_crypto.h */
-+
-+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
-+{
-+ get_random_bytes(buffer, length);
-+}
-+
-+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
-+{
-+ struct crypto_blkcipher *tfm;
-+ struct blkcipher_desc desc;
-+ struct scatterlist sgd;
-+ struct scatterlist sgs;
-+
-+ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
-+ if (tfm == NULL) {
-+ printk("failed to load transform for aes CBC\n");
-+ return -1;
-+ }
-+
-+ crypto_blkcipher_setkey(tfm, key, keylen);
-+ crypto_blkcipher_set_iv(tfm, iv, 16);
-+
-+ sg_init_one(&sgd, out, messagelen);
-+ sg_init_one(&sgs, message, messagelen);
-+
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
-+ crypto_free_blkcipher(tfm);
-+ DWC_ERROR("AES CBC encryption failed");
-+ return -1;
-+ }
-+
-+ crypto_free_blkcipher(tfm);
-+ return 0;
-+}
-+
-+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
-+{
-+ struct crypto_hash *tfm;
-+ struct hash_desc desc;
-+ struct scatterlist sg;
-+
-+ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
-+ if (IS_ERR(tfm)) {
-+ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
-+ return 0;
-+ }
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ sg_init_one(&sg, message, len);
-+ crypto_hash_digest(&desc, &sg, len, out);
-+ crypto_free_hash(tfm);
-+
-+ return 1;
-+}
-+
-+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
-+ uint8_t *key, uint32_t keylen, uint8_t *out)
-+{
-+ struct crypto_hash *tfm;
-+ struct hash_desc desc;
-+ struct scatterlist sg;
-+
-+ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
-+ if (IS_ERR(tfm)) {
-+ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
-+ return 0;
-+ }
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ sg_init_one(&sg, message, messagelen);
-+ crypto_hash_setkey(tfm, key, keylen);
-+ crypto_hash_digest(&desc, &sg, messagelen, out);
-+ crypto_free_hash(tfm);
-+
-+ return 1;
-+}
-+
-+#endif /* DWC_CRYPTOLIB */
-+
-+
-+/* Byte Ordering Conversions */
-+
-+uint32_t DWC_CPU_TO_LE32(uint32_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_CPU_TO_BE32(uint32_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_LE32_TO_CPU(uint32_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_BE32_TO_CPU(uint32_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint16_t DWC_CPU_TO_LE16(uint16_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_CPU_TO_BE16(uint16_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_LE16_TO_CPU(uint16_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_BE16_TO_CPU(uint16_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+
-+/* Registers */
-+
-+uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ return bus_space_read_4(io->iot, io->ioh, ior);
-+}
-+
-+#if 0
-+uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ return bus_space_read_8(io->iot, io->ioh, ior);
-+}
-+#endif
-+
-+void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_4(io->iot, io->ioh, ior, value);
-+}
-+
-+#if 0
-+void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_8(io->iot, io->ioh, ior, value);
-+}
-+#endif
-+
-+void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
-+ uint32_t set_mask)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_4(io->iot, io->ioh, ior,
-+ (bus_space_read_4(io->iot, io->ioh, ior) &
-+ ~clear_mask) | set_mask);
-+}
-+
-+#if 0
-+void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
-+ uint64_t set_mask)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_8(io->iot, io->ioh, ior,
-+ (bus_space_read_8(io->iot, io->ioh, ior) &
-+ ~clear_mask) | set_mask);
-+}
-+#endif
-+
-+
-+/* Locking */
-+
-+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
-+{
-+ struct mtx *sl = DWC_ALLOC(sizeof(*sl));
-+
-+ if (!sl) {
-+ DWC_ERROR("Cannot allocate memory for spinlock");
-+ return NULL;
-+ }
-+
-+ mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
-+ return (dwc_spinlock_t *)sl;
-+}
-+
-+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
-+{
-+ struct mtx *sl = (struct mtx *)lock;
-+
-+ mtx_destroy(sl);
-+ DWC_FREE(sl);
-+}
-+
-+void DWC_SPINLOCK(dwc_spinlock_t *lock)
-+{
-+ mtx_lock_spin((struct mtx *)lock); // ???
-+}
-+
-+void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
-+{
-+ mtx_unlock_spin((struct mtx *)lock); // ???
-+}
-+
-+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
-+{
-+ mtx_lock_spin((struct mtx *)lock);
-+}
-+
-+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
-+{
-+ mtx_unlock_spin((struct mtx *)lock);
-+}
-+
-+dwc_mutex_t *DWC_MUTEX_ALLOC(void)
-+{
-+ struct mtx *m;
-+ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
-+
-+ if (!mutex) {
-+ DWC_ERROR("Cannot allocate memory for mutex");
-+ return NULL;
-+ }
-+
-+ m = (struct mtx *)mutex;
-+ mtx_init(m, "dw3mtx", NULL, MTX_DEF);
-+ return mutex;
-+}
-+
-+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
-+#else
-+void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
-+{
-+ mtx_destroy((struct mtx *)mutex);
-+ DWC_FREE(mutex);
-+}
-+#endif
-+
-+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
-+{
-+ struct mtx *m = (struct mtx *)mutex;
-+
-+ mtx_lock(m);
-+}
-+
-+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
-+{
-+ struct mtx *m = (struct mtx *)mutex;
-+
-+ return mtx_trylock(m);
-+}
-+
-+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
-+{
-+ struct mtx *m = (struct mtx *)mutex;
-+
-+ mtx_unlock(m);
-+}
-+
-+
-+/* Timing */
-+
-+void DWC_UDELAY(uint32_t usecs)
-+{
-+ DELAY(usecs);
-+}
-+
-+void DWC_MDELAY(uint32_t msecs)
-+{
-+ do {
-+ DELAY(1000);
-+ } while (--msecs);
-+}
-+
-+void DWC_MSLEEP(uint32_t msecs)
-+{
-+ struct timeval tv;
-+
-+ tv.tv_sec = msecs / 1000;
-+ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
-+ pause("dw3slp", tvtohz(&tv));
-+}
-+
-+uint32_t DWC_TIME(void)
-+{
-+ struct timeval tv;
-+
-+ microuptime(&tv); // or getmicrouptime? (less precise, but faster)
-+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-+}
-+
-+
-+/* Timers */
-+
-+struct dwc_timer {
-+ struct callout t;
-+ char *name;
-+ dwc_spinlock_t *lock;
-+ dwc_timer_callback_t cb;
-+ void *data;
-+};
-+
-+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
-+{
-+ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
-+
-+ if (!t) {
-+ DWC_ERROR("Cannot allocate memory for timer");
-+ return NULL;
-+ }
-+
-+ callout_init(&t->t, 1);
-+
-+ t->name = DWC_STRDUP(name);
-+ if (!t->name) {
-+ DWC_ERROR("Cannot allocate memory for timer->name");
-+ goto no_name;
-+ }
-+
-+ t->lock = DWC_SPINLOCK_ALLOC();
-+ if (!t->lock) {
-+ DWC_ERROR("Cannot allocate memory for lock");
-+ goto no_lock;
-+ }
-+
-+ t->cb = cb;
-+ t->data = data;
-+
-+ return t;
-+
-+ no_lock:
-+ DWC_FREE(t->name);
-+ no_name:
-+ DWC_FREE(t);
-+
-+ return NULL;
-+}
-+
-+void DWC_TIMER_FREE(dwc_timer_t *timer)
-+{
-+ callout_stop(&timer->t);
-+ DWC_SPINLOCK_FREE(timer->lock);
-+ DWC_FREE(timer->name);
-+ DWC_FREE(timer);
-+}
-+
-+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
-+{
-+ struct timeval tv;
-+
-+ tv.tv_sec = time / 1000;
-+ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
-+ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
-+}
-+
-+void DWC_TIMER_CANCEL(dwc_timer_t *timer)
-+{
-+ callout_stop(&timer->t);
-+}
-+
-+
-+/* Wait Queues */
-+
-+struct dwc_waitq {
-+ struct mtx lock;
-+ int abort;
-+};
-+
-+dwc_waitq_t *DWC_WAITQ_ALLOC(void)
-+{
-+ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
-+
-+ if (!wq) {
-+ DWC_ERROR("Cannot allocate memory for waitqueue");
-+ return NULL;
-+ }
-+
-+ mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
-+ wq->abort = 0;
-+
-+ return wq;
-+}
-+
-+void DWC_WAITQ_FREE(dwc_waitq_t *wq)
-+{
-+ mtx_destroy(&wq->lock);
-+ DWC_FREE(wq);
-+}
-+
-+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
-+{
-+// intrmask_t ipl;
-+ int result = 0;
-+
-+ mtx_lock(&wq->lock);
-+// ipl = splbio();
-+
-+ /* Skip the sleep if already aborted or triggered */
-+ if (!wq->abort && !cond(data)) {
-+// splx(ipl);
-+ result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
-+// ipl = splbio();
-+ }
-+
-+ if (result == ERESTART) { // signaled - restart
-+ result = -DWC_E_RESTART;
-+
-+ } else if (result == EINTR) { // signaled - interrupt
-+ result = -DWC_E_ABORT;
-+
-+ } else if (wq->abort) {
-+ result = -DWC_E_ABORT;
-+
-+ } else {
-+ result = 0;
-+ }
-+
-+ wq->abort = 0;
-+// splx(ipl);
-+ mtx_unlock(&wq->lock);
-+ return result;
-+}
-+
-+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
-+ void *data, int32_t msecs)
-+{
-+ struct timeval tv, tv1, tv2;
-+// intrmask_t ipl;
-+ int result = 0;
-+
-+ tv.tv_sec = msecs / 1000;
-+ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
-+
-+ mtx_lock(&wq->lock);
-+// ipl = splbio();
-+
-+ /* Skip the sleep if already aborted or triggered */
-+ if (!wq->abort && !cond(data)) {
-+// splx(ipl);
-+ getmicrouptime(&tv1);
-+ result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
-+ getmicrouptime(&tv2);
-+// ipl = splbio();
-+ }
-+
-+ if (result == 0) { // awoken
-+ if (wq->abort) {
-+ result = -DWC_E_ABORT;
-+ } else {
-+ tv2.tv_usec -= tv1.tv_usec;
-+ if (tv2.tv_usec < 0) {
-+ tv2.tv_usec += 1000000;
-+ tv2.tv_sec--;
-+ }
-+
-+ tv2.tv_sec -= tv1.tv_sec;
-+ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
-+ result = msecs - result;
-+ if (result <= 0)
-+ result = 1;
-+ }
-+ } else if (result == ERESTART) { // signaled - restart
-+ result = -DWC_E_RESTART;
-+
-+ } else if (result == EINTR) { // signaled - interrupt
-+ result = -DWC_E_ABORT;
-+
-+ } else { // timed out
-+ result = -DWC_E_TIMEOUT;
-+ }
-+
-+ wq->abort = 0;
-+// splx(ipl);
-+ mtx_unlock(&wq->lock);
-+ return result;
-+}
-+
-+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
-+{
-+ wakeup(wq);
-+}
-+
-+void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
-+{
-+// intrmask_t ipl;
-+
-+ mtx_lock(&wq->lock);
-+// ipl = splbio();
-+ wq->abort = 1;
-+ wakeup(wq);
-+// splx(ipl);
-+ mtx_unlock(&wq->lock);
-+}
-+
-+
-+/* Threading */
-+
-+struct dwc_thread {
-+ struct proc *proc;
-+ int abort;
-+};
-+
-+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
-+{
-+ int retval;
-+ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
-+
-+ if (!thread) {
-+ return NULL;
-+ }
-+
-+ thread->abort = 0;
-+ retval = kthread_create((void (*)(void *))func, data, &thread->proc,
-+ RFPROC | RFNOWAIT, 0, "%s", name);
-+ if (retval) {
-+ DWC_FREE(thread);
-+ return NULL;
-+ }
-+
-+ return thread;
-+}
-+
-+int DWC_THREAD_STOP(dwc_thread_t *thread)
-+{
-+ int retval;
-+
-+ thread->abort = 1;
-+ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
-+
-+ if (retval == 0) {
-+ /* DWC_THREAD_EXIT() will free the thread struct */
-+ return 0;
-+ }
-+
-+ /* NOTE: We leak the thread struct if thread doesn't die */
-+
-+ if (retval == EWOULDBLOCK) {
-+ return -DWC_E_TIMEOUT;
-+ }
-+
-+ return -DWC_E_UNKNOWN;
-+}
-+
-+dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
-+{
-+ return thread->abort;
-+}
-+
-+void DWC_THREAD_EXIT(dwc_thread_t *thread)
-+{
-+ wakeup(&thread->abort);
-+ DWC_FREE(thread);
-+ kthread_exit(0);
-+}
-+
-+
-+/* tasklets
-+ - Runs in interrupt context (cannot sleep)
-+ - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
-+ - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
-+ */
-+struct dwc_tasklet {
-+ struct task t;
-+ dwc_tasklet_callback_t cb;
-+ void *data;
-+};
-+
-+static void tasklet_callback(void *data, int pending) // what to do with pending ???
-+{
-+ dwc_tasklet_t *task = (dwc_tasklet_t *)data;
-+
-+ task->cb(task->data);
-+}
-+
-+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
-+{
-+ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
-+
-+ if (task) {
-+ task->cb = cb;
-+ task->data = data;
-+ TASK_INIT(&task->t, 0, tasklet_callback, task);
-+ } else {
-+ DWC_ERROR("Cannot allocate memory for tasklet");
-+ }
-+
-+ return task;
-+}
-+
-+void DWC_TASK_FREE(dwc_tasklet_t *task)
-+{
-+ taskqueue_drain(taskqueue_fast, &task->t); // ???
-+ DWC_FREE(task);
-+}
-+
-+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
-+{
-+ /* Uses predefined system queue */
-+ taskqueue_enqueue_fast(taskqueue_fast, &task->t);
-+}
-+
-+
-+/* workqueues
-+ - Runs in process context (can sleep)
-+ */
-+typedef struct work_container {
-+ dwc_work_callback_t cb;
-+ void *data;
-+ dwc_workq_t *wq;
-+ char *name;
-+ int hz;
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_ENTRY(work_container) entry;
-+#endif
-+ struct task task;
-+} work_container_t;
-+
-+#ifdef DEBUG
-+DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
-+#endif
-+
-+struct dwc_workq {
-+ struct taskqueue *taskq;
-+ dwc_spinlock_t *lock;
-+ dwc_waitq_t *waitq;
-+ int pending;
-+
-+#ifdef DEBUG
-+ struct work_container_queue entries;
-+#endif
-+};
-+
-+static void do_work(void *data, int pending) // what to do with pending ???
-+{
-+ work_container_t *container = (work_container_t *)data;
-+ dwc_workq_t *wq = container->wq;
-+ dwc_irqflags_t flags;
-+
-+ if (container->hz) {
-+ pause("dw3wrk", container->hz);
-+ }
-+
-+ container->cb(container->data);
-+ DWC_DEBUG("Work done: %s, container=%p", container->name, container);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
-+#endif
-+ if (container->name)
-+ DWC_FREE(container->name);
-+ DWC_FREE(container);
-+ wq->pending--;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+}
-+
-+static int work_done(void *data)
-+{
-+ dwc_workq_t *workq = (dwc_workq_t *)data;
-+
-+ return workq->pending == 0;
-+}
-+
-+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
-+{
-+ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
-+}
-+
-+dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
-+{
-+ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
-+
-+ if (!wq) {
-+ DWC_ERROR("Cannot allocate memory for workqueue");
-+ return NULL;
-+ }
-+
-+ wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
-+ if (!wq->taskq) {
-+ DWC_ERROR("Cannot allocate memory for taskqueue");
-+ goto no_taskq;
-+ }
-+
-+ wq->pending = 0;
-+
-+ wq->lock = DWC_SPINLOCK_ALLOC();
-+ if (!wq->lock) {
-+ DWC_ERROR("Cannot allocate memory for spinlock");
-+ goto no_lock;
-+ }
-+
-+ wq->waitq = DWC_WAITQ_ALLOC();
-+ if (!wq->waitq) {
-+ DWC_ERROR("Cannot allocate memory for waitqueue");
-+ goto no_waitq;
-+ }
-+
-+ taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_INIT(&wq->entries);
-+#endif
-+ return wq;
-+
-+ no_waitq:
-+ DWC_SPINLOCK_FREE(wq->lock);
-+ no_lock:
-+ taskqueue_free(wq->taskq);
-+ no_taskq:
-+ DWC_FREE(wq);
-+
-+ return NULL;
-+}
-+
-+void DWC_WORKQ_FREE(dwc_workq_t *wq)
-+{
-+#ifdef DEBUG
-+ dwc_irqflags_t flags;
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+
-+ if (wq->pending != 0) {
-+ struct work_container *container;
-+
-+ DWC_ERROR("Destroying work queue with pending work");
-+
-+ DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
-+ DWC_ERROR("Work %s still pending", container->name);
-+ }
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+#endif
-+ DWC_WAITQ_FREE(wq->waitq);
-+ DWC_SPINLOCK_FREE(wq->lock);
-+ taskqueue_free(wq->taskq);
-+ DWC_FREE(wq);
-+}
-+
-+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
-+ char *format, ...)
-+{
-+ dwc_irqflags_t flags;
-+ work_container_t *container;
-+ static char name[128];
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VSNPRINTF(name, 128, format, args);
-+ va_end(args);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending++;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+
-+ container = DWC_ALLOC_ATOMIC(sizeof(*container));
-+ if (!container) {
-+ DWC_ERROR("Cannot allocate memory for container");
-+ return;
-+ }
-+
-+ container->name = DWC_STRDUP(name);
-+ if (!container->name) {
-+ DWC_ERROR("Cannot allocate memory for container->name");
-+ DWC_FREE(container);
-+ return;
-+ }
-+
-+ container->cb = cb;
-+ container->data = data;
-+ container->wq = wq;
-+ container->hz = 0;
-+
-+ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
-+
-+ TASK_INIT(&container->task, 0, do_work, container);
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
-+#endif
-+ taskqueue_enqueue_fast(wq->taskq, &container->task);
-+}
-+
-+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
-+ void *data, uint32_t time, char *format, ...)
-+{
-+ dwc_irqflags_t flags;
-+ work_container_t *container;
-+ static char name[128];
-+ struct timeval tv;
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VSNPRINTF(name, 128, format, args);
-+ va_end(args);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending++;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+
-+ container = DWC_ALLOC_ATOMIC(sizeof(*container));
-+ if (!container) {
-+ DWC_ERROR("Cannot allocate memory for container");
-+ return;
-+ }
-+
-+ container->name = DWC_STRDUP(name);
-+ if (!container->name) {
-+ DWC_ERROR("Cannot allocate memory for container->name");
-+ DWC_FREE(container);
-+ return;
-+ }
-+
-+ container->cb = cb;
-+ container->data = data;
-+ container->wq = wq;
-+
-+ tv.tv_sec = time / 1000;
-+ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
-+ container->hz = tvtohz(&tv);
-+
-+ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
-+
-+ TASK_INIT(&container->task, 0, do_work, container);
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
-+#endif
-+ taskqueue_enqueue_fast(wq->taskq, &container->task);
-+}
-+
-+int DWC_WORKQ_PENDING(dwc_workq_t *wq)
-+{
-+ return wq->pending;
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_common_linux.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_common_linux.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_common_linux.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_common_linux.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1431 @@
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kthread.h>
-+
-+#ifdef DWC_CCLIB
-+# include "dwc_cc.h"
-+#endif
-+
-+#ifdef DWC_CRYPTOLIB
-+# include "dwc_modpow.h"
-+# include "dwc_dh.h"
-+# include "dwc_crypto.h"
-+#endif
-+
-+#ifdef DWC_NOTIFYLIB
-+# include "dwc_notifier.h"
-+#endif
-+
-+/* OS-Level Implementations */
-+
-+/* This is the Linux kernel implementation of the DWC platform library. */
-+#include <linux/moduleparam.h>
-+#include <linux/ctype.h>
-+#include <linux/crypto.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/cdev.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/jiffies.h>
-+#include <linux/list.h>
-+#include <linux/pci.h>
-+#include <linux/random.h>
-+#include <linux/scatterlist.h>
-+#include <linux/slab.h>
-+#include <linux/stat.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/usb.h>
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+# include <linux/usb/gadget.h>
-+#else
-+# include <linux/usb_gadget.h>
-+#endif
-+
-+#include <asm/io.h>
-+#include <asm/page.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include "dwc_os.h"
-+#include "dwc_list.h"
-+
-+
-+/* MISC */
-+
-+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
-+{
-+ return memset(dest, byte, size);
-+}
-+
-+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
-+{
-+ return memcpy(dest, src, size);
-+}
-+
-+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
-+{
-+ return memmove(dest, src, size);
-+}
-+
-+int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
-+{
-+ return memcmp(m1, m2, size);
-+}
-+
-+int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
-+{
-+ return strncmp(s1, s2, size);
-+}
-+
-+int DWC_STRCMP(void *s1, void *s2)
-+{
-+ return strcmp(s1, s2);
-+}
-+
-+int DWC_STRLEN(char const *str)
-+{
-+ return strlen(str);
-+}
-+
-+char *DWC_STRCPY(char *to, char const *from)
-+{
-+ return strcpy(to, from);
-+}
-+
-+char *DWC_STRDUP(char const *str)
-+{
-+ int len = DWC_STRLEN(str) + 1;
-+ char *new = DWC_ALLOC_ATOMIC(len);
-+
-+ if (!new) {
-+ return NULL;
-+ }
-+
-+ DWC_MEMCPY(new, str, len);
-+ return new;
-+}
-+
-+int DWC_ATOI(const char *str, int32_t *value)
-+{
-+ char *end = NULL;
-+
-+ *value = simple_strtol(str, &end, 0);
-+ if (*end == '\0') {
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+int DWC_ATOUI(const char *str, uint32_t *value)
-+{
-+ char *end = NULL;
-+
-+ *value = simple_strtoul(str, &end, 0);
-+ if (*end == '\0') {
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+
-+#ifdef DWC_UTFLIB
-+/* From usbstring.c */
-+
-+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
-+{
-+ int count = 0;
-+ u8 c;
-+ u16 uchar;
-+
-+ /* this insists on correct encodings, though not minimal ones.
-+ * BUT it currently rejects legit 4-byte UTF-8 code points,
-+ * which need surrogate pairs. (Unicode 3.1 can use them.)
-+ */
-+ while (len != 0 && (c = (u8) *s++) != 0) {
-+ if (unlikely(c & 0x80)) {
-+ // 2-byte sequence:
-+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-+ if ((c & 0xe0) == 0xc0) {
-+ uchar = (c & 0x1f) << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ // 3-byte sequence (most CJKV characters):
-+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-+ } else if ((c & 0xf0) == 0xe0) {
-+ uchar = (c & 0x0f) << 12;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ /* no bogus surrogates */
-+ if (0xd800 <= uchar && uchar <= 0xdfff)
-+ goto fail;
-+
-+ // 4-byte sequence (surrogate pairs, currently rare):
-+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-+ // (uuuuu = wwww + 1)
-+ // FIXME accept the surrogate code points (only)
-+ } else
-+ goto fail;
-+ } else
-+ uchar = c;
-+ put_unaligned (cpu_to_le16 (uchar), cp++);
-+ count++;
-+ len--;
-+ }
-+ return count;
-+fail:
-+ return -1;
-+}
-+#endif /* DWC_UTFLIB */
-+
-+
-+/* dwc_debug.h */
-+
-+dwc_bool_t DWC_IN_IRQ(void)
-+{
-+ return in_irq();
-+}
-+
-+dwc_bool_t DWC_IN_BH(void)
-+{
-+ return in_softirq();
-+}
-+
-+void DWC_VPRINTF(char *format, va_list args)
-+{
-+ vprintk(format, args);
-+}
-+
-+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
-+{
-+ return vsnprintf(str, size, format, args);
-+}
-+
-+void DWC_PRINTF(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+int DWC_SPRINTF(char *buffer, char *format, ...)
-+{
-+ int retval;
-+ va_list args;
-+
-+ va_start(args, format);
-+ retval = vsprintf(buffer, format, args);
-+ va_end(args);
-+ return retval;
-+}
-+
-+int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
-+{
-+ int retval;
-+ va_list args;
-+
-+ va_start(args, format);
-+ retval = vsnprintf(buffer, size, format, args);
-+ va_end(args);
-+ return retval;
-+}
-+
-+void __DWC_WARN(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_PRINTF(KERN_WARNING);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+void __DWC_ERROR(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_PRINTF(KERN_ERR);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+void DWC_EXCEPTION(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_PRINTF(KERN_ERR);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+ BUG_ON(1);
-+}
-+
-+#ifdef DEBUG
-+void __DWC_DEBUG(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_PRINTF(KERN_DEBUG);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+#endif
-+
-+
-+/* dwc_mem.h */
-+
-+#if 0
-+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
-+ uint32_t align,
-+ uint32_t alloc)
-+{
-+ struct dma_pool *pool = dma_pool_create("Pool", NULL,
-+ size, align, alloc);
-+ return (dwc_pool_t *)pool;
-+}
-+
-+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
-+{
-+ dma_pool_destroy((struct dma_pool *)pool);
-+}
-+
-+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
-+{
-+ return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
-+}
-+
-+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
-+{
-+ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
-+ memset(..);
-+}
-+
-+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
-+{
-+ dma_pool_free(pool, vaddr, daddr);
-+}
-+#endif
-+
-+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
-+{
-+#ifdef xxCOSIM /* Only works for 32-bit cosim */
-+ void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
-+#else
-+ void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
-+#endif
-+ if (!buf) {
-+ return NULL;
-+ }
-+
-+ memset(buf, 0, (size_t)size);
-+ return buf;
-+}
-+
-+void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
-+{
-+ void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
-+ if (!buf) {
-+ return NULL;
-+ }
-+ memset(buf, 0, (size_t)size);
-+ return buf;
-+}
-+
-+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
-+{
-+ dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
-+}
-+
-+void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
-+{
-+ return kzalloc(size, GFP_KERNEL);
-+}
-+
-+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
-+{
-+ return kzalloc(size, GFP_ATOMIC);
-+}
-+
-+void __DWC_FREE(void *mem_ctx, void *addr)
-+{
-+ kfree(addr);
-+}
-+
-+
-+#ifdef DWC_CRYPTOLIB
-+/* dwc_crypto.h */
-+
-+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
-+{
-+ get_random_bytes(buffer, length);
-+}
-+
-+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
-+{
-+ struct crypto_blkcipher *tfm;
-+ struct blkcipher_desc desc;
-+ struct scatterlist sgd;
-+ struct scatterlist sgs;
-+
-+ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
-+ if (tfm == NULL) {
-+ printk("failed to load transform for aes CBC\n");
-+ return -1;
-+ }
-+
-+ crypto_blkcipher_setkey(tfm, key, keylen);
-+ crypto_blkcipher_set_iv(tfm, iv, 16);
-+
-+ sg_init_one(&sgd, out, messagelen);
-+ sg_init_one(&sgs, message, messagelen);
-+
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
-+ crypto_free_blkcipher(tfm);
-+ DWC_ERROR("AES CBC encryption failed");
-+ return -1;
-+ }
-+
-+ crypto_free_blkcipher(tfm);
-+ return 0;
-+}
-+
-+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
-+{
-+ struct crypto_hash *tfm;
-+ struct hash_desc desc;
-+ struct scatterlist sg;
-+
-+ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
-+ if (IS_ERR(tfm)) {
-+ DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
-+ return 0;
-+ }
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ sg_init_one(&sg, message, len);
-+ crypto_hash_digest(&desc, &sg, len, out);
-+ crypto_free_hash(tfm);
-+
-+ return 1;
-+}
-+
-+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
-+ uint8_t *key, uint32_t keylen, uint8_t *out)
-+{
-+ struct crypto_hash *tfm;
-+ struct hash_desc desc;
-+ struct scatterlist sg;
-+
-+ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
-+ if (IS_ERR(tfm)) {
-+ DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
-+ return 0;
-+ }
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ sg_init_one(&sg, message, messagelen);
-+ crypto_hash_setkey(tfm, key, keylen);
-+ crypto_hash_digest(&desc, &sg, messagelen, out);
-+ crypto_free_hash(tfm);
-+
-+ return 1;
-+}
-+#endif /* DWC_CRYPTOLIB */
-+
-+
-+/* Byte Ordering Conversions */
-+
-+uint32_t DWC_CPU_TO_LE32(uint32_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_CPU_TO_BE32(uint32_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_LE32_TO_CPU(uint32_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_BE32_TO_CPU(uint32_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint16_t DWC_CPU_TO_LE16(uint16_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_CPU_TO_BE16(uint16_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_LE16_TO_CPU(uint16_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_BE16_TO_CPU(uint16_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+
-+/* Registers */
-+
-+uint32_t DWC_READ_REG32(uint32_t volatile *reg)
-+{
-+ return readl(reg);
-+}
-+
-+#if 0
-+uint64_t DWC_READ_REG64(uint64_t volatile *reg)
-+{
-+}
-+#endif
-+
-+void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
-+{
-+ writel(value, reg);
-+}
-+
-+#if 0
-+void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
-+{
-+}
-+#endif
-+
-+void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
-+{
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ local_fiq_disable();
-+ writel((readl(reg) & ~clear_mask) | set_mask, reg);
-+ local_irq_restore(flags);
-+}
-+
-+#if 0
-+void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
-+{
-+}
-+#endif
-+
-+
-+/* Locking */
-+
-+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
-+{
-+ spinlock_t *sl = (spinlock_t *)1;
-+
-+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
-+ sl = DWC_ALLOC(sizeof(*sl));
-+ if (!sl) {
-+ DWC_ERROR("Cannot allocate memory for spinlock\n");
-+ return NULL;
-+ }
-+
-+ spin_lock_init(sl);
-+#endif
-+ return (dwc_spinlock_t *)sl;
-+}
-+
-+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
-+{
-+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
-+ DWC_FREE(lock);
-+#endif
-+}
-+
-+void DWC_SPINLOCK(dwc_spinlock_t *lock)
-+{
-+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
-+ spin_lock((spinlock_t *)lock);
-+#endif
-+}
-+
-+void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
-+{
-+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
-+ spin_unlock((spinlock_t *)lock);
-+#endif
-+}
-+
-+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
-+{
-+ dwc_irqflags_t f;
-+
-+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
-+ spin_lock_irqsave((spinlock_t *)lock, f);
-+#else
-+ local_irq_save(f);
-+#endif
-+ *flags = f;
-+}
-+
-+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
-+{
-+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
-+ spin_unlock_irqrestore((spinlock_t *)lock, flags);
-+#else
-+ local_irq_restore(flags);
-+#endif
-+}
-+
-+dwc_mutex_t *DWC_MUTEX_ALLOC(void)
-+{
-+ struct mutex *m;
-+ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
-+
-+ if (!mutex) {
-+ DWC_ERROR("Cannot allocate memory for mutex\n");
-+ return NULL;
-+ }
-+
-+ m = (struct mutex *)mutex;
-+ mutex_init(m);
-+ return mutex;
-+}
-+
-+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
-+#else
-+void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
-+{
-+ mutex_destroy((struct mutex *)mutex);
-+ DWC_FREE(mutex);
-+}
-+#endif
-+
-+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
-+{
-+ struct mutex *m = (struct mutex *)mutex;
-+ mutex_lock(m);
-+}
-+
-+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
-+{
-+ struct mutex *m = (struct mutex *)mutex;
-+ return mutex_trylock(m);
-+}
-+
-+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
-+{
-+ struct mutex *m = (struct mutex *)mutex;
-+ mutex_unlock(m);
-+}
-+
-+
-+/* Timing */
-+
-+void DWC_UDELAY(uint32_t usecs)
-+{
-+ udelay(usecs);
-+}
-+
-+void DWC_MDELAY(uint32_t msecs)
-+{
-+ mdelay(msecs);
-+}
-+
-+void DWC_MSLEEP(uint32_t msecs)
-+{
-+ msleep(msecs);
-+}
-+
-+uint32_t DWC_TIME(void)
-+{
-+ return jiffies_to_msecs(jiffies);
-+}
-+
-+
-+/* Timers */
-+
-+struct dwc_timer {
-+ struct timer_list *t;
-+ char *name;
-+ dwc_timer_callback_t cb;
-+ void *data;
-+ uint8_t scheduled;
-+ dwc_spinlock_t *lock;
-+};
-+
-+static void timer_callback(unsigned long data)
-+{
-+ dwc_timer_t *timer = (dwc_timer_t *)data;
-+ dwc_irqflags_t flags;
-+
-+ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
-+ timer->scheduled = 0;
-+ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
-+ DWC_DEBUGC("Timer %s callback", timer->name);
-+ timer->cb(timer->data);
-+}
-+
-+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
-+{
-+ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
-+
-+ if (!t) {
-+ DWC_ERROR("Cannot allocate memory for timer");
-+ return NULL;
-+ }
-+
-+ t->t = DWC_ALLOC(sizeof(*t->t));
-+ if (!t->t) {
-+ DWC_ERROR("Cannot allocate memory for timer->t");
-+ goto no_timer;
-+ }
-+
-+ t->name = DWC_STRDUP(name);
-+ if (!t->name) {
-+ DWC_ERROR("Cannot allocate memory for timer->name");
-+ goto no_name;
-+ }
-+
-+ t->lock = DWC_SPINLOCK_ALLOC();
-+ if (!t->lock) {
-+ DWC_ERROR("Cannot allocate memory for lock");
-+ goto no_lock;
-+ }
-+
-+ t->scheduled = 0;
-+ t->t->base = &boot_tvec_bases;
-+ t->t->expires = jiffies;
-+ setup_timer(t->t, timer_callback, (unsigned long)t);
-+
-+ t->cb = cb;
-+ t->data = data;
-+
-+ return t;
-+
-+ no_lock:
-+ DWC_FREE(t->name);
-+ no_name:
-+ DWC_FREE(t->t);
-+ no_timer:
-+ DWC_FREE(t);
-+ return NULL;
-+}
-+
-+void DWC_TIMER_FREE(dwc_timer_t *timer)
-+{
-+ dwc_irqflags_t flags;
-+
-+ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
-+
-+ if (timer->scheduled) {
-+ del_timer(timer->t);
-+ timer->scheduled = 0;
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
-+ DWC_SPINLOCK_FREE(timer->lock);
-+ DWC_FREE(timer->t);
-+ DWC_FREE(timer->name);
-+ DWC_FREE(timer);
-+}
-+
-+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
-+{
-+ dwc_irqflags_t flags;
-+
-+ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
-+
-+ if (!timer->scheduled) {
-+ timer->scheduled = 1;
-+ DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
-+ timer->t->expires = jiffies + msecs_to_jiffies(time);
-+ add_timer(timer->t);
-+ } else {
-+ DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
-+ mod_timer(timer->t, jiffies + msecs_to_jiffies(time));
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
-+}
-+
-+void DWC_TIMER_CANCEL(dwc_timer_t *timer)
-+{
-+ del_timer(timer->t);
-+}
-+
-+
-+/* Wait Queues */
-+
-+struct dwc_waitq {
-+ wait_queue_head_t queue;
-+ int abort;
-+};
-+
-+dwc_waitq_t *DWC_WAITQ_ALLOC(void)
-+{
-+ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
-+
-+ if (!wq) {
-+ DWC_ERROR("Cannot allocate memory for waitqueue\n");
-+ return NULL;
-+ }
-+
-+ init_waitqueue_head(&wq->queue);
-+ wq->abort = 0;
-+ return wq;
-+}
-+
-+void DWC_WAITQ_FREE(dwc_waitq_t *wq)
-+{
-+ DWC_FREE(wq);
-+}
-+
-+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
-+{
-+ int result = wait_event_interruptible(wq->queue,
-+ cond(data) || wq->abort);
-+ if (result == -ERESTARTSYS) {
-+ wq->abort = 0;
-+ return -DWC_E_RESTART;
-+ }
-+
-+ if (wq->abort == 1) {
-+ wq->abort = 0;
-+ return -DWC_E_ABORT;
-+ }
-+
-+ wq->abort = 0;
-+
-+ if (result == 0) {
-+ return 0;
-+ }
-+
-+ return -DWC_E_UNKNOWN;
-+}
-+
-+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
-+ void *data, int32_t msecs)
-+{
-+ int32_t tmsecs;
-+ int result = wait_event_interruptible_timeout(wq->queue,
-+ cond(data) || wq->abort,
-+ msecs_to_jiffies(msecs));
-+ if (result == -ERESTARTSYS) {
-+ wq->abort = 0;
-+ return -DWC_E_RESTART;
-+ }
-+
-+ if (wq->abort == 1) {
-+ wq->abort = 0;
-+ return -DWC_E_ABORT;
-+ }
-+
-+ wq->abort = 0;
-+
-+ if (result > 0) {
-+ tmsecs = jiffies_to_msecs(result);
-+ if (!tmsecs) {
-+ return 1;
-+ }
-+
-+ return tmsecs;
-+ }
-+
-+ if (result == 0) {
-+ return -DWC_E_TIMEOUT;
-+ }
-+
-+ return -DWC_E_UNKNOWN;
-+}
-+
-+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
-+{
-+ wq->abort = 0;
-+ wake_up_interruptible(&wq->queue);
-+}
-+
-+void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
-+{
-+ wq->abort = 1;
-+ wake_up_interruptible(&wq->queue);
-+}
-+
-+
-+/* Threading */
-+
-+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
-+{
-+ struct task_struct *thread = kthread_run(func, data, name);
-+
-+ if (thread == ERR_PTR(-ENOMEM)) {
-+ return NULL;
-+ }
-+
-+ return (dwc_thread_t *)thread;
-+}
-+
-+int DWC_THREAD_STOP(dwc_thread_t *thread)
-+{
-+ return kthread_stop((struct task_struct *)thread);
-+}
-+
-+dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
-+{
-+ return kthread_should_stop();
-+}
-+
-+
-+/* tasklets
-+ - run in interrupt context (cannot sleep)
-+ - each tasklet runs on a single CPU
-+ - different tasklets can be running simultaneously on different CPUs
-+ */
-+struct dwc_tasklet {
-+ struct tasklet_struct t;
-+ dwc_tasklet_callback_t cb;
-+ void *data;
-+};
-+
-+static void tasklet_callback(unsigned long data)
-+{
-+ dwc_tasklet_t *t = (dwc_tasklet_t *)data;
-+ t->cb(t->data);
-+}
-+
-+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
-+{
-+ dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
-+
-+ if (t) {
-+ t->cb = cb;
-+ t->data = data;
-+ tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
-+ } else {
-+ DWC_ERROR("Cannot allocate memory for tasklet\n");
-+ }
-+
-+ return t;
-+}
-+
-+void DWC_TASK_FREE(dwc_tasklet_t *task)
-+{
-+ DWC_FREE(task);
-+}
-+
-+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
-+{
-+ tasklet_schedule(&task->t);
-+}
-+
-+void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task)
-+{
-+ tasklet_hi_schedule(&task->t);
-+}
-+
-+
-+/* workqueues
-+ - run in process context (can sleep)
-+ */
-+typedef struct work_container {
-+ dwc_work_callback_t cb;
-+ void *data;
-+ dwc_workq_t *wq;
-+ char *name;
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_ENTRY(work_container) entry;
-+#endif
-+ struct delayed_work work;
-+} work_container_t;
-+
-+#ifdef DEBUG
-+DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
-+#endif
-+
-+struct dwc_workq {
-+ struct workqueue_struct *wq;
-+ dwc_spinlock_t *lock;
-+ dwc_waitq_t *waitq;
-+ int pending;
-+
-+#ifdef DEBUG
-+ struct work_container_queue entries;
-+#endif
-+};
-+
-+static void do_work(struct work_struct *work)
-+{
-+ dwc_irqflags_t flags;
-+ struct delayed_work *dw = container_of(work, struct delayed_work, work);
-+ work_container_t *container = container_of(dw, struct work_container, work);
-+ dwc_workq_t *wq = container->wq;
-+
-+ container->cb(container->data);
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
-+#endif
-+ DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
-+ if (container->name) {
-+ DWC_FREE(container->name);
-+ }
-+ DWC_FREE(container);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending--;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+}
-+
-+static int work_done(void *data)
-+{
-+ dwc_workq_t *workq = (dwc_workq_t *)data;
-+ return workq->pending == 0;
-+}
-+
-+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
-+{
-+ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
-+}
-+
-+dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
-+{
-+ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
-+
-+ if (!wq) {
-+ return NULL;
-+ }
-+
-+ wq->wq = create_singlethread_workqueue(name);
-+ if (!wq->wq) {
-+ goto no_wq;
-+ }
-+
-+ wq->pending = 0;
-+
-+ wq->lock = DWC_SPINLOCK_ALLOC();
-+ if (!wq->lock) {
-+ goto no_lock;
-+ }
-+
-+ wq->waitq = DWC_WAITQ_ALLOC();
-+ if (!wq->waitq) {
-+ goto no_waitq;
-+ }
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_INIT(&wq->entries);
-+#endif
-+ return wq;
-+
-+ no_waitq:
-+ DWC_SPINLOCK_FREE(wq->lock);
-+ no_lock:
-+ destroy_workqueue(wq->wq);
-+ no_wq:
-+ DWC_FREE(wq);
-+
-+ return NULL;
-+}
-+
-+void DWC_WORKQ_FREE(dwc_workq_t *wq)
-+{
-+#ifdef DEBUG
-+ if (wq->pending != 0) {
-+ struct work_container *wc;
-+ DWC_ERROR("Destroying work queue with pending work");
-+ DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
-+ DWC_ERROR("Work %s still pending", wc->name);
-+ }
-+ }
-+#endif
-+ destroy_workqueue(wq->wq);
-+ DWC_SPINLOCK_FREE(wq->lock);
-+ DWC_WAITQ_FREE(wq->waitq);
-+ DWC_FREE(wq);
-+}
-+
-+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
-+ char *format, ...)
-+{
-+ dwc_irqflags_t flags;
-+ work_container_t *container;
-+ static char name[128];
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VSNPRINTF(name, 128, format, args);
-+ va_end(args);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending++;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+
-+ container = DWC_ALLOC_ATOMIC(sizeof(*container));
-+ if (!container) {
-+ DWC_ERROR("Cannot allocate memory for container\n");
-+ return;
-+ }
-+
-+ container->name = DWC_STRDUP(name);
-+ if (!container->name) {
-+ DWC_ERROR("Cannot allocate memory for container->name\n");
-+ DWC_FREE(container);
-+ return;
-+ }
-+
-+ container->cb = cb;
-+ container->data = data;
-+ container->wq = wq;
-+ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
-+ INIT_WORK(&container->work.work, do_work);
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
-+#endif
-+ queue_work(wq->wq, &container->work.work);
-+}
-+
-+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
-+ void *data, uint32_t time, char *format, ...)
-+{
-+ dwc_irqflags_t flags;
-+ work_container_t *container;
-+ static char name[128];
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VSNPRINTF(name, 128, format, args);
-+ va_end(args);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending++;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+
-+ container = DWC_ALLOC_ATOMIC(sizeof(*container));
-+ if (!container) {
-+ DWC_ERROR("Cannot allocate memory for container\n");
-+ return;
-+ }
-+
-+ container->name = DWC_STRDUP(name);
-+ if (!container->name) {
-+ DWC_ERROR("Cannot allocate memory for container->name\n");
-+ DWC_FREE(container);
-+ return;
-+ }
-+
-+ container->cb = cb;
-+ container->data = data;
-+ container->wq = wq;
-+ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
-+ INIT_DELAYED_WORK(&container->work, do_work);
-+
-+#ifdef DEBUG
-+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
-+#endif
-+ queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
-+}
-+
-+int DWC_WORKQ_PENDING(dwc_workq_t *wq)
-+{
-+ return wq->pending;
-+}
-+
-+
-+#ifdef DWC_LIBMODULE
-+
-+#ifdef DWC_CCLIB
-+/* CC */
-+EXPORT_SYMBOL(dwc_cc_if_alloc);
-+EXPORT_SYMBOL(dwc_cc_if_free);
-+EXPORT_SYMBOL(dwc_cc_clear);
-+EXPORT_SYMBOL(dwc_cc_add);
-+EXPORT_SYMBOL(dwc_cc_remove);
-+EXPORT_SYMBOL(dwc_cc_change);
-+EXPORT_SYMBOL(dwc_cc_data_for_save);
-+EXPORT_SYMBOL(dwc_cc_restore_from_data);
-+EXPORT_SYMBOL(dwc_cc_match_chid);
-+EXPORT_SYMBOL(dwc_cc_match_cdid);
-+EXPORT_SYMBOL(dwc_cc_ck);
-+EXPORT_SYMBOL(dwc_cc_chid);
-+EXPORT_SYMBOL(dwc_cc_cdid);
-+EXPORT_SYMBOL(dwc_cc_name);
-+#endif /* DWC_CCLIB */
-+
-+#ifdef DWC_CRYPTOLIB
-+# ifndef CONFIG_MACH_IPMATE
-+/* Modpow */
-+EXPORT_SYMBOL(dwc_modpow);
-+
-+/* DH */
-+EXPORT_SYMBOL(dwc_dh_modpow);
-+EXPORT_SYMBOL(dwc_dh_derive_keys);
-+EXPORT_SYMBOL(dwc_dh_pk);
-+# endif /* CONFIG_MACH_IPMATE */
-+
-+/* Crypto */
-+EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
-+EXPORT_SYMBOL(dwc_wusb_cmf);
-+EXPORT_SYMBOL(dwc_wusb_prf);
-+EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
-+EXPORT_SYMBOL(dwc_wusb_gen_nonce);
-+EXPORT_SYMBOL(dwc_wusb_gen_key);
-+EXPORT_SYMBOL(dwc_wusb_gen_mic);
-+#endif /* DWC_CRYPTOLIB */
-+
-+/* Notification */
-+#ifdef DWC_NOTIFYLIB
-+EXPORT_SYMBOL(dwc_alloc_notification_manager);
-+EXPORT_SYMBOL(dwc_free_notification_manager);
-+EXPORT_SYMBOL(dwc_register_notifier);
-+EXPORT_SYMBOL(dwc_unregister_notifier);
-+EXPORT_SYMBOL(dwc_add_observer);
-+EXPORT_SYMBOL(dwc_remove_observer);
-+EXPORT_SYMBOL(dwc_notify);
-+#endif
-+
-+/* Memory Debugging Routines */
-+#ifdef DWC_DEBUG_MEMORY
-+EXPORT_SYMBOL(dwc_alloc_debug);
-+EXPORT_SYMBOL(dwc_alloc_atomic_debug);
-+EXPORT_SYMBOL(dwc_free_debug);
-+EXPORT_SYMBOL(dwc_dma_alloc_debug);
-+EXPORT_SYMBOL(dwc_dma_free_debug);
-+#endif
-+
-+EXPORT_SYMBOL(DWC_MEMSET);
-+EXPORT_SYMBOL(DWC_MEMCPY);
-+EXPORT_SYMBOL(DWC_MEMMOVE);
-+EXPORT_SYMBOL(DWC_MEMCMP);
-+EXPORT_SYMBOL(DWC_STRNCMP);
-+EXPORT_SYMBOL(DWC_STRCMP);
-+EXPORT_SYMBOL(DWC_STRLEN);
-+EXPORT_SYMBOL(DWC_STRCPY);
-+EXPORT_SYMBOL(DWC_STRDUP);
-+EXPORT_SYMBOL(DWC_ATOI);
-+EXPORT_SYMBOL(DWC_ATOUI);
-+
-+#ifdef DWC_UTFLIB
-+EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
-+#endif /* DWC_UTFLIB */
-+
-+EXPORT_SYMBOL(DWC_IN_IRQ);
-+EXPORT_SYMBOL(DWC_IN_BH);
-+EXPORT_SYMBOL(DWC_VPRINTF);
-+EXPORT_SYMBOL(DWC_VSNPRINTF);
-+EXPORT_SYMBOL(DWC_PRINTF);
-+EXPORT_SYMBOL(DWC_SPRINTF);
-+EXPORT_SYMBOL(DWC_SNPRINTF);
-+EXPORT_SYMBOL(__DWC_WARN);
-+EXPORT_SYMBOL(__DWC_ERROR);
-+EXPORT_SYMBOL(DWC_EXCEPTION);
-+
-+#ifdef DEBUG
-+EXPORT_SYMBOL(__DWC_DEBUG);
-+#endif
-+
-+EXPORT_SYMBOL(__DWC_DMA_ALLOC);
-+EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
-+EXPORT_SYMBOL(__DWC_DMA_FREE);
-+EXPORT_SYMBOL(__DWC_ALLOC);
-+EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
-+EXPORT_SYMBOL(__DWC_FREE);
-+
-+#ifdef DWC_CRYPTOLIB
-+EXPORT_SYMBOL(DWC_RANDOM_BYTES);
-+EXPORT_SYMBOL(DWC_AES_CBC);
-+EXPORT_SYMBOL(DWC_SHA256);
-+EXPORT_SYMBOL(DWC_HMAC_SHA256);
-+#endif
-+
-+EXPORT_SYMBOL(DWC_CPU_TO_LE32);
-+EXPORT_SYMBOL(DWC_CPU_TO_BE32);
-+EXPORT_SYMBOL(DWC_LE32_TO_CPU);
-+EXPORT_SYMBOL(DWC_BE32_TO_CPU);
-+EXPORT_SYMBOL(DWC_CPU_TO_LE16);
-+EXPORT_SYMBOL(DWC_CPU_TO_BE16);
-+EXPORT_SYMBOL(DWC_LE16_TO_CPU);
-+EXPORT_SYMBOL(DWC_BE16_TO_CPU);
-+EXPORT_SYMBOL(DWC_READ_REG32);
-+EXPORT_SYMBOL(DWC_WRITE_REG32);
-+EXPORT_SYMBOL(DWC_MODIFY_REG32);
-+
-+#if 0
-+EXPORT_SYMBOL(DWC_READ_REG64);
-+EXPORT_SYMBOL(DWC_WRITE_REG64);
-+EXPORT_SYMBOL(DWC_MODIFY_REG64);
-+#endif
-+
-+EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
-+EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
-+EXPORT_SYMBOL(DWC_SPINLOCK);
-+EXPORT_SYMBOL(DWC_SPINUNLOCK);
-+EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
-+EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
-+EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
-+
-+#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
-+EXPORT_SYMBOL(DWC_MUTEX_FREE);
-+#endif
-+
-+EXPORT_SYMBOL(DWC_MUTEX_LOCK);
-+EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
-+EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
-+EXPORT_SYMBOL(DWC_UDELAY);
-+EXPORT_SYMBOL(DWC_MDELAY);
-+EXPORT_SYMBOL(DWC_MSLEEP);
-+EXPORT_SYMBOL(DWC_TIME);
-+EXPORT_SYMBOL(DWC_TIMER_ALLOC);
-+EXPORT_SYMBOL(DWC_TIMER_FREE);
-+EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
-+EXPORT_SYMBOL(DWC_TIMER_CANCEL);
-+EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
-+EXPORT_SYMBOL(DWC_WAITQ_FREE);
-+EXPORT_SYMBOL(DWC_WAITQ_WAIT);
-+EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
-+EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
-+EXPORT_SYMBOL(DWC_WAITQ_ABORT);
-+EXPORT_SYMBOL(DWC_THREAD_RUN);
-+EXPORT_SYMBOL(DWC_THREAD_STOP);
-+EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
-+EXPORT_SYMBOL(DWC_TASK_ALLOC);
-+EXPORT_SYMBOL(DWC_TASK_FREE);
-+EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
-+EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
-+EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
-+EXPORT_SYMBOL(DWC_WORKQ_FREE);
-+EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
-+EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
-+EXPORT_SYMBOL(DWC_WORKQ_PENDING);
-+
-+static int dwc_common_port_init_module(void)
-+{
-+ int result = 0;
-+
-+ printk(KERN_DEBUG "Module dwc_common_port init\n" );
-+
-+#ifdef DWC_DEBUG_MEMORY
-+ result = dwc_memory_debug_start(NULL);
-+ if (result) {
-+ printk(KERN_ERR
-+ "dwc_memory_debug_start() failed with error %d\n",
-+ result);
-+ return result;
-+ }
-+#endif
-+
-+#ifdef DWC_NOTIFYLIB
-+ result = dwc_alloc_notification_manager(NULL, NULL);
-+ if (result) {
-+ printk(KERN_ERR
-+ "dwc_alloc_notification_manager() failed with error %d\n",
-+ result);
-+ return result;
-+ }
-+#endif
-+ return result;
-+}
-+
-+static void dwc_common_port_exit_module(void)
-+{
-+ printk(KERN_DEBUG "Module dwc_common_port exit\n" );
-+
-+#ifdef DWC_NOTIFYLIB
-+ dwc_free_notification_manager();
-+#endif
-+
-+#ifdef DWC_DEBUG_MEMORY
-+ dwc_memory_debug_stop();
-+#endif
-+}
-+
-+module_init(dwc_common_port_init_module);
-+module_exit(dwc_common_port_exit_module);
-+
-+MODULE_DESCRIPTION("DWC Common Library - Portable version");
-+MODULE_AUTHOR("Synopsys Inc.");
-+MODULE_LICENSE ("GPL");
-+
-+#endif /* DWC_LIBMODULE */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1275 @@
-+#include "dwc_os.h"
-+#include "dwc_list.h"
-+
-+#ifdef DWC_CCLIB
-+# include "dwc_cc.h"
-+#endif
-+
-+#ifdef DWC_CRYPTOLIB
-+# include "dwc_modpow.h"
-+# include "dwc_dh.h"
-+# include "dwc_crypto.h"
-+#endif
-+
-+#ifdef DWC_NOTIFYLIB
-+# include "dwc_notifier.h"
-+#endif
-+
-+/* OS-Level Implementations */
-+
-+/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
-+
-+
-+/* MISC */
-+
-+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
-+{
-+ return memset(dest, byte, size);
-+}
-+
-+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
-+{
-+ return memcpy(dest, src, size);
-+}
-+
-+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
-+{
-+ bcopy(src, dest, size);
-+ return dest;
-+}
-+
-+int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
-+{
-+ return memcmp(m1, m2, size);
-+}
-+
-+int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
-+{
-+ return strncmp(s1, s2, size);
-+}
-+
-+int DWC_STRCMP(void *s1, void *s2)
-+{
-+ return strcmp(s1, s2);
-+}
-+
-+int DWC_STRLEN(char const *str)
-+{
-+ return strlen(str);
-+}
-+
-+char *DWC_STRCPY(char *to, char const *from)
-+{
-+ return strcpy(to, from);
-+}
-+
-+char *DWC_STRDUP(char const *str)
-+{
-+ int len = DWC_STRLEN(str) + 1;
-+ char *new = DWC_ALLOC_ATOMIC(len);
-+
-+ if (!new) {
-+ return NULL;
-+ }
-+
-+ DWC_MEMCPY(new, str, len);
-+ return new;
-+}
-+
-+int DWC_ATOI(char *str, int32_t *value)
-+{
-+ char *end = NULL;
-+
-+ /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
-+ * should be equivalent on 2's complement machines
-+ */
-+ *value = strtoul(str, &end, 0);
-+ if (*end == '\0') {
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+int DWC_ATOUI(char *str, uint32_t *value)
-+{
-+ char *end = NULL;
-+
-+ *value = strtoul(str, &end, 0);
-+ if (*end == '\0') {
-+ return 0;
-+ }
-+
-+ return -1;
-+}
-+
-+
-+#ifdef DWC_UTFLIB
-+/* From usbstring.c */
-+
-+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
-+{
-+ int count = 0;
-+ u8 c;
-+ u16 uchar;
-+
-+ /* this insists on correct encodings, though not minimal ones.
-+ * BUT it currently rejects legit 4-byte UTF-8 code points,
-+ * which need surrogate pairs. (Unicode 3.1 can use them.)
-+ */
-+ while (len != 0 && (c = (u8) *s++) != 0) {
-+ if (unlikely(c & 0x80)) {
-+ // 2-byte sequence:
-+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-+ if ((c & 0xe0) == 0xc0) {
-+ uchar = (c & 0x1f) << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ // 3-byte sequence (most CJKV characters):
-+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-+ } else if ((c & 0xf0) == 0xe0) {
-+ uchar = (c & 0x0f) << 12;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ /* no bogus surrogates */
-+ if (0xd800 <= uchar && uchar <= 0xdfff)
-+ goto fail;
-+
-+ // 4-byte sequence (surrogate pairs, currently rare):
-+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-+ // (uuuuu = wwww + 1)
-+ // FIXME accept the surrogate code points (only)
-+ } else
-+ goto fail;
-+ } else
-+ uchar = c;
-+ put_unaligned (cpu_to_le16 (uchar), cp++);
-+ count++;
-+ len--;
-+ }
-+ return count;
-+fail:
-+ return -1;
-+}
-+
-+#endif /* DWC_UTFLIB */
-+
-+
-+/* dwc_debug.h */
-+
-+dwc_bool_t DWC_IN_IRQ(void)
-+{
-+// return in_irq();
-+ return 0;
-+}
-+
-+dwc_bool_t DWC_IN_BH(void)
-+{
-+// return in_softirq();
-+ return 0;
-+}
-+
-+void DWC_VPRINTF(char *format, va_list args)
-+{
-+ vprintf(format, args);
-+}
-+
-+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
-+{
-+ return vsnprintf(str, size, format, args);
-+}
-+
-+void DWC_PRINTF(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+int DWC_SPRINTF(char *buffer, char *format, ...)
-+{
-+ int retval;
-+ va_list args;
-+
-+ va_start(args, format);
-+ retval = vsprintf(buffer, format, args);
-+ va_end(args);
-+ return retval;
-+}
-+
-+int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
-+{
-+ int retval;
-+ va_list args;
-+
-+ va_start(args, format);
-+ retval = vsnprintf(buffer, size, format, args);
-+ va_end(args);
-+ return retval;
-+}
-+
-+void __DWC_WARN(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+void __DWC_ERROR(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+
-+void DWC_EXCEPTION(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+// BUG_ON(1); ???
-+}
-+
-+#ifdef DEBUG
-+void __DWC_DEBUG(char *format, ...)
-+{
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VPRINTF(format, args);
-+ va_end(args);
-+}
-+#endif
-+
-+
-+/* dwc_mem.h */
-+
-+#if 0
-+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
-+ uint32_t align,
-+ uint32_t alloc)
-+{
-+ struct dma_pool *pool = dma_pool_create("Pool", NULL,
-+ size, align, alloc);
-+ return (dwc_pool_t *)pool;
-+}
-+
-+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
-+{
-+ dma_pool_destroy((struct dma_pool *)pool);
-+}
-+
-+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
-+{
-+// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
-+ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
-+}
-+
-+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
-+{
-+ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
-+ memset(..);
-+}
-+
-+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
-+{
-+ dma_pool_free(pool, vaddr, daddr);
-+}
-+#endif
-+
-+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
-+{
-+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
-+ int error;
-+
-+ error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
-+ sizeof(dma->segs) / sizeof(dma->segs[0]),
-+ &dma->nsegs, BUS_DMA_NOWAIT);
-+ if (error) {
-+ printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
-+ (uintmax_t)size, error);
-+ goto fail_0;
-+ }
-+
-+ error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
-+ (caddr_t *)&dma->dma_vaddr,
-+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
-+ if (error) {
-+ printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
-+ goto fail_1;
-+ }
-+
-+ error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
-+ BUS_DMA_NOWAIT, &dma->dma_map);
-+ if (error) {
-+ printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
-+ goto fail_2;
-+ }
-+
-+ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
-+ size, NULL, BUS_DMA_NOWAIT);
-+ if (error) {
-+ printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
-+ goto fail_3;
-+ }
-+
-+ dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
-+ *dma_addr = dma->dma_paddr;
-+ return dma->dma_vaddr;
-+
-+fail_3:
-+ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
-+fail_2:
-+ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
-+fail_1:
-+ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
-+fail_0:
-+ dma->dma_map = NULL;
-+ dma->dma_vaddr = NULL;
-+ dma->nsegs = 0;
-+
-+ return NULL;
-+}
-+
-+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
-+{
-+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
-+
-+ if (dma->dma_map != NULL) {
-+ bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
-+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
-+ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
-+ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
-+ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
-+ dma->dma_paddr = 0;
-+ dma->dma_map = NULL;
-+ dma->dma_vaddr = NULL;
-+ dma->nsegs = 0;
-+ }
-+}
-+
-+void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
-+{
-+ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
-+}
-+
-+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
-+{
-+ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
-+}
-+
-+void __DWC_FREE(void *mem_ctx, void *addr)
-+{
-+ free(addr, M_DEVBUF);
-+}
-+
-+
-+#ifdef DWC_CRYPTOLIB
-+/* dwc_crypto.h */
-+
-+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
-+{
-+ get_random_bytes(buffer, length);
-+}
-+
-+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
-+{
-+ struct crypto_blkcipher *tfm;
-+ struct blkcipher_desc desc;
-+ struct scatterlist sgd;
-+ struct scatterlist sgs;
-+
-+ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
-+ if (tfm == NULL) {
-+ printk("failed to load transform for aes CBC\n");
-+ return -1;
-+ }
-+
-+ crypto_blkcipher_setkey(tfm, key, keylen);
-+ crypto_blkcipher_set_iv(tfm, iv, 16);
-+
-+ sg_init_one(&sgd, out, messagelen);
-+ sg_init_one(&sgs, message, messagelen);
-+
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
-+ crypto_free_blkcipher(tfm);
-+ DWC_ERROR("AES CBC encryption failed");
-+ return -1;
-+ }
-+
-+ crypto_free_blkcipher(tfm);
-+ return 0;
-+}
-+
-+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
-+{
-+ struct crypto_hash *tfm;
-+ struct hash_desc desc;
-+ struct scatterlist sg;
-+
-+ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
-+ if (IS_ERR(tfm)) {
-+ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
-+ return 0;
-+ }
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ sg_init_one(&sg, message, len);
-+ crypto_hash_digest(&desc, &sg, len, out);
-+ crypto_free_hash(tfm);
-+
-+ return 1;
-+}
-+
-+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
-+ uint8_t *key, uint32_t keylen, uint8_t *out)
-+{
-+ struct crypto_hash *tfm;
-+ struct hash_desc desc;
-+ struct scatterlist sg;
-+
-+ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
-+ if (IS_ERR(tfm)) {
-+ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
-+ return 0;
-+ }
-+ desc.tfm = tfm;
-+ desc.flags = 0;
-+
-+ sg_init_one(&sg, message, messagelen);
-+ crypto_hash_setkey(tfm, key, keylen);
-+ crypto_hash_digest(&desc, &sg, messagelen, out);
-+ crypto_free_hash(tfm);
-+
-+ return 1;
-+}
-+
-+#endif /* DWC_CRYPTOLIB */
-+
-+
-+/* Byte Ordering Conversions */
-+
-+uint32_t DWC_CPU_TO_LE32(uint32_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_CPU_TO_BE32(uint32_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_LE32_TO_CPU(uint32_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint32_t DWC_BE32_TO_CPU(uint32_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+
-+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
-+#endif
-+}
-+
-+uint16_t DWC_CPU_TO_LE16(uint16_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_CPU_TO_BE16(uint16_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_LE16_TO_CPU(uint16_t *p)
-+{
-+#ifdef __LITTLE_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+uint16_t DWC_BE16_TO_CPU(uint16_t *p)
-+{
-+#ifdef __BIG_ENDIAN
-+ return *p;
-+#else
-+ uint8_t *u_p = (uint8_t *)p;
-+ return (u_p[1] | (u_p[0] << 8));
-+#endif
-+}
-+
-+
-+/* Registers */
-+
-+uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ return bus_space_read_4(io->iot, io->ioh, ior);
-+}
-+
-+#if 0
-+uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ return bus_space_read_8(io->iot, io->ioh, ior);
-+}
-+#endif
-+
-+void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_4(io->iot, io->ioh, ior, value);
-+}
-+
-+#if 0
-+void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_8(io->iot, io->ioh, ior, value);
-+}
-+#endif
-+
-+void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
-+ uint32_t set_mask)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_4(io->iot, io->ioh, ior,
-+ (bus_space_read_4(io->iot, io->ioh, ior) &
-+ ~clear_mask) | set_mask);
-+}
-+
-+#if 0
-+void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
-+ uint64_t set_mask)
-+{
-+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
-+ bus_size_t ior = (bus_size_t)reg;
-+
-+ bus_space_write_8(io->iot, io->ioh, ior,
-+ (bus_space_read_8(io->iot, io->ioh, ior) &
-+ ~clear_mask) | set_mask);
-+}
-+#endif
-+
-+
-+/* Locking */
-+
-+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
-+{
-+ struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
-+
-+ if (!sl) {
-+ DWC_ERROR("Cannot allocate memory for spinlock");
-+ return NULL;
-+ }
-+
-+ simple_lock_init(sl);
-+ return (dwc_spinlock_t *)sl;
-+}
-+
-+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
-+{
-+ struct simplelock *sl = (struct simplelock *)lock;
-+
-+ DWC_FREE(sl);
-+}
-+
-+void DWC_SPINLOCK(dwc_spinlock_t *lock)
-+{
-+ simple_lock((struct simplelock *)lock);
-+}
-+
-+void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
-+{
-+ simple_unlock((struct simplelock *)lock);
-+}
-+
-+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
-+{
-+ simple_lock((struct simplelock *)lock);
-+ *flags = splbio();
-+}
-+
-+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
-+{
-+ splx(flags);
-+ simple_unlock((struct simplelock *)lock);
-+}
-+
-+dwc_mutex_t *DWC_MUTEX_ALLOC(void)
-+{
-+ dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
-+
-+ if (!mutex) {
-+ DWC_ERROR("Cannot allocate memory for mutex");
-+ return NULL;
-+ }
-+
-+ lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
-+ return mutex;
-+}
-+
-+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
-+#else
-+void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
-+{
-+ DWC_FREE(mutex);
-+}
-+#endif
-+
-+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
-+{
-+ lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
-+}
-+
-+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
-+{
-+ int status;
-+
-+ status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
-+ return status == 0;
-+}
-+
-+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
-+{
-+ lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
-+}
-+
-+
-+/* Timing */
-+
-+void DWC_UDELAY(uint32_t usecs)
-+{
-+ DELAY(usecs);
-+}
-+
-+void DWC_MDELAY(uint32_t msecs)
-+{
-+ do {
-+ DELAY(1000);
-+ } while (--msecs);
-+}
-+
-+void DWC_MSLEEP(uint32_t msecs)
-+{
-+ struct timeval tv;
-+
-+ tv.tv_sec = msecs / 1000;
-+ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
-+ tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
-+}
-+
-+uint32_t DWC_TIME(void)
-+{
-+ struct timeval tv;
-+
-+ microuptime(&tv); // or getmicrouptime? (less precise, but faster)
-+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-+}
-+
-+
-+/* Timers */
-+
-+struct dwc_timer {
-+ struct callout t;
-+ char *name;
-+ dwc_spinlock_t *lock;
-+ dwc_timer_callback_t cb;
-+ void *data;
-+};
-+
-+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
-+{
-+ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
-+
-+ if (!t) {
-+ DWC_ERROR("Cannot allocate memory for timer");
-+ return NULL;
-+ }
-+
-+ callout_init(&t->t);
-+
-+ t->name = DWC_STRDUP(name);
-+ if (!t->name) {
-+ DWC_ERROR("Cannot allocate memory for timer->name");
-+ goto no_name;
-+ }
-+
-+ t->lock = DWC_SPINLOCK_ALLOC();
-+ if (!t->lock) {
-+ DWC_ERROR("Cannot allocate memory for timer->lock");
-+ goto no_lock;
-+ }
-+
-+ t->cb = cb;
-+ t->data = data;
-+
-+ return t;
-+
-+ no_lock:
-+ DWC_FREE(t->name);
-+ no_name:
-+ DWC_FREE(t);
-+
-+ return NULL;
-+}
-+
-+void DWC_TIMER_FREE(dwc_timer_t *timer)
-+{
-+ callout_stop(&timer->t);
-+ DWC_SPINLOCK_FREE(timer->lock);
-+ DWC_FREE(timer->name);
-+ DWC_FREE(timer);
-+}
-+
-+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
-+{
-+ struct timeval tv;
-+
-+ tv.tv_sec = time / 1000;
-+ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
-+ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
-+}
-+
-+void DWC_TIMER_CANCEL(dwc_timer_t *timer)
-+{
-+ callout_stop(&timer->t);
-+}
-+
-+
-+/* Wait Queues */
-+
-+struct dwc_waitq {
-+ struct simplelock lock;
-+ int abort;
-+};
-+
-+dwc_waitq_t *DWC_WAITQ_ALLOC(void)
-+{
-+ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
-+
-+ if (!wq) {
-+ DWC_ERROR("Cannot allocate memory for waitqueue");
-+ return NULL;
-+ }
-+
-+ simple_lock_init(&wq->lock);
-+ wq->abort = 0;
-+
-+ return wq;
-+}
-+
-+void DWC_WAITQ_FREE(dwc_waitq_t *wq)
-+{
-+ DWC_FREE(wq);
-+}
-+
-+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
-+{
-+ int ipl;
-+ int result = 0;
-+
-+ simple_lock(&wq->lock);
-+ ipl = splbio();
-+
-+ /* Skip the sleep if already aborted or triggered */
-+ if (!wq->abort && !cond(data)) {
-+ splx(ipl);
-+ result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
-+ ipl = splbio();
-+ }
-+
-+ if (result == 0) { // awoken
-+ if (wq->abort) {
-+ wq->abort = 0;
-+ result = -DWC_E_ABORT;
-+ } else {
-+ result = 0;
-+ }
-+
-+ splx(ipl);
-+ simple_unlock(&wq->lock);
-+ } else {
-+ wq->abort = 0;
-+ splx(ipl);
-+ simple_unlock(&wq->lock);
-+
-+ if (result == ERESTART) { // signaled - restart
-+ result = -DWC_E_RESTART;
-+ } else { // signaled - must be EINTR
-+ result = -DWC_E_ABORT;
-+ }
-+ }
-+
-+ return result;
-+}
-+
-+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
-+ void *data, int32_t msecs)
-+{
-+ struct timeval tv, tv1, tv2;
-+ int ipl;
-+ int result = 0;
-+
-+ tv.tv_sec = msecs / 1000;
-+ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
-+
-+ simple_lock(&wq->lock);
-+ ipl = splbio();
-+
-+ /* Skip the sleep if already aborted or triggered */
-+ if (!wq->abort && !cond(data)) {
-+ splx(ipl);
-+ getmicrouptime(&tv1);
-+ result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
-+ getmicrouptime(&tv2);
-+ ipl = splbio();
-+ }
-+
-+ if (result == 0) { // awoken
-+ if (wq->abort) {
-+ wq->abort = 0;
-+ splx(ipl);
-+ simple_unlock(&wq->lock);
-+ result = -DWC_E_ABORT;
-+ } else {
-+ splx(ipl);
-+ simple_unlock(&wq->lock);
-+
-+ tv2.tv_usec -= tv1.tv_usec;
-+ if (tv2.tv_usec < 0) {
-+ tv2.tv_usec += 1000000;
-+ tv2.tv_sec--;
-+ }
-+
-+ tv2.tv_sec -= tv1.tv_sec;
-+ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
-+ result = msecs - result;
-+ if (result <= 0)
-+ result = 1;
-+ }
-+ } else {
-+ wq->abort = 0;
-+ splx(ipl);
-+ simple_unlock(&wq->lock);
-+
-+ if (result == ERESTART) { // signaled - restart
-+ result = -DWC_E_RESTART;
-+
-+ } else if (result == EINTR) { // signaled - interrupt
-+ result = -DWC_E_ABORT;
-+
-+ } else { // timed out
-+ result = -DWC_E_TIMEOUT;
-+ }
-+ }
-+
-+ return result;
-+}
-+
-+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
-+{
-+ wakeup(wq);
-+}
-+
-+void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
-+{
-+ int ipl;
-+
-+ simple_lock(&wq->lock);
-+ ipl = splbio();
-+ wq->abort = 1;
-+ wakeup(wq);
-+ splx(ipl);
-+ simple_unlock(&wq->lock);
-+}
-+
-+
-+/* Threading */
-+
-+struct dwc_thread {
-+ struct proc *proc;
-+ int abort;
-+};
-+
-+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
-+{
-+ int retval;
-+ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
-+
-+ if (!thread) {
-+ return NULL;
-+ }
-+
-+ thread->abort = 0;
-+ retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
-+ "%s", name);
-+ if (retval) {
-+ DWC_FREE(thread);
-+ return NULL;
-+ }
-+
-+ return thread;
-+}
-+
-+int DWC_THREAD_STOP(dwc_thread_t *thread)
-+{
-+ int retval;
-+
-+ thread->abort = 1;
-+ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
-+
-+ if (retval == 0) {
-+ /* DWC_THREAD_EXIT() will free the thread struct */
-+ return 0;
-+ }
-+
-+ /* NOTE: We leak the thread struct if thread doesn't die */
-+
-+ if (retval == EWOULDBLOCK) {
-+ return -DWC_E_TIMEOUT;
-+ }
-+
-+ return -DWC_E_UNKNOWN;
-+}
-+
-+dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
-+{
-+ return thread->abort;
-+}
-+
-+void DWC_THREAD_EXIT(dwc_thread_t *thread)
-+{
-+ wakeup(&thread->abort);
-+ DWC_FREE(thread);
-+ kthread_exit(0);
-+}
-+
-+/* tasklets
-+ - Runs in interrupt context (cannot sleep)
-+ - Each tasklet runs on a single CPU
-+ - Different tasklets can be running simultaneously on different CPUs
-+ [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
-+ halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
-+ */
-+struct dwc_tasklet {
-+ dwc_tasklet_callback_t cb;
-+ void *data;
-+};
-+
-+static void tasklet_callback(void *data)
-+{
-+ dwc_tasklet_t *task = (dwc_tasklet_t *)data;
-+
-+ task->cb(task->data);
-+}
-+
-+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
-+{
-+ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
-+
-+ if (task) {
-+ task->cb = cb;
-+ task->data = data;
-+ } else {
-+ DWC_ERROR("Cannot allocate memory for tasklet");
-+ }
-+
-+ return task;
-+}
-+
-+void DWC_TASK_FREE(dwc_tasklet_t *task)
-+{
-+ DWC_FREE(task);
-+}
-+
-+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
-+{
-+ tasklet_callback(task);
-+}
-+
-+
-+/* workqueues
-+ - Runs in process context (can sleep)
-+ */
-+typedef struct work_container {
-+ dwc_work_callback_t cb;
-+ void *data;
-+ dwc_workq_t *wq;
-+ char *name;
-+ int hz;
-+ struct work task;
-+} work_container_t;
-+
-+struct dwc_workq {
-+ struct workqueue *taskq;
-+ dwc_spinlock_t *lock;
-+ dwc_waitq_t *waitq;
-+ int pending;
-+ struct work_container *container;
-+};
-+
-+static void do_work(struct work *task, void *data)
-+{
-+ dwc_workq_t *wq = (dwc_workq_t *)data;
-+ work_container_t *container = wq->container;
-+ dwc_irqflags_t flags;
-+
-+ if (container->hz) {
-+ tsleep(container, 0, "dw3wrk", container->hz);
-+ }
-+
-+ container->cb(container->data);
-+ DWC_DEBUG("Work done: %s, container=%p", container->name, container);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ if (container->name)
-+ DWC_FREE(container->name);
-+ DWC_FREE(container);
-+ wq->pending--;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+}
-+
-+static int work_done(void *data)
-+{
-+ dwc_workq_t *workq = (dwc_workq_t *)data;
-+
-+ return workq->pending == 0;
-+}
-+
-+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
-+{
-+ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
-+}
-+
-+dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
-+{
-+ int result;
-+ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
-+
-+ if (!wq) {
-+ DWC_ERROR("Cannot allocate memory for workqueue");
-+ return NULL;
-+ }
-+
-+ result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
-+ IPL_BIO, 0);
-+ if (result) {
-+ DWC_ERROR("Cannot create workqueue");
-+ goto no_taskq;
-+ }
-+
-+ wq->pending = 0;
-+
-+ wq->lock = DWC_SPINLOCK_ALLOC();
-+ if (!wq->lock) {
-+ DWC_ERROR("Cannot allocate memory for spinlock");
-+ goto no_lock;
-+ }
-+
-+ wq->waitq = DWC_WAITQ_ALLOC();
-+ if (!wq->waitq) {
-+ DWC_ERROR("Cannot allocate memory for waitqueue");
-+ goto no_waitq;
-+ }
-+
-+ return wq;
-+
-+ no_waitq:
-+ DWC_SPINLOCK_FREE(wq->lock);
-+ no_lock:
-+ workqueue_destroy(wq->taskq);
-+ no_taskq:
-+ DWC_FREE(wq);
-+
-+ return NULL;
-+}
-+
-+void DWC_WORKQ_FREE(dwc_workq_t *wq)
-+{
-+#ifdef DEBUG
-+ dwc_irqflags_t flags;
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+
-+ if (wq->pending != 0) {
-+ struct work_container *container = wq->container;
-+
-+ DWC_ERROR("Destroying work queue with pending work");
-+
-+ if (container && container->name) {
-+ DWC_ERROR("Work %s still pending", container->name);
-+ }
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+#endif
-+ DWC_WAITQ_FREE(wq->waitq);
-+ DWC_SPINLOCK_FREE(wq->lock);
-+ workqueue_destroy(wq->taskq);
-+ DWC_FREE(wq);
-+}
-+
-+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
-+ char *format, ...)
-+{
-+ dwc_irqflags_t flags;
-+ work_container_t *container;
-+ static char name[128];
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VSNPRINTF(name, 128, format, args);
-+ va_end(args);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending++;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+
-+ container = DWC_ALLOC_ATOMIC(sizeof(*container));
-+ if (!container) {
-+ DWC_ERROR("Cannot allocate memory for container");
-+ return;
-+ }
-+
-+ container->name = DWC_STRDUP(name);
-+ if (!container->name) {
-+ DWC_ERROR("Cannot allocate memory for container->name");
-+ DWC_FREE(container);
-+ return;
-+ }
-+
-+ container->cb = cb;
-+ container->data = data;
-+ container->wq = wq;
-+ container->hz = 0;
-+ wq->container = container;
-+
-+ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
-+ workqueue_enqueue(wq->taskq, &container->task);
-+}
-+
-+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
-+ void *data, uint32_t time, char *format, ...)
-+{
-+ dwc_irqflags_t flags;
-+ work_container_t *container;
-+ static char name[128];
-+ struct timeval tv;
-+ va_list args;
-+
-+ va_start(args, format);
-+ DWC_VSNPRINTF(name, 128, format, args);
-+ va_end(args);
-+
-+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
-+ wq->pending++;
-+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
-+ DWC_WAITQ_TRIGGER(wq->waitq);
-+
-+ container = DWC_ALLOC_ATOMIC(sizeof(*container));
-+ if (!container) {
-+ DWC_ERROR("Cannot allocate memory for container");
-+ return;
-+ }
-+
-+ container->name = DWC_STRDUP(name);
-+ if (!container->name) {
-+ DWC_ERROR("Cannot allocate memory for container->name");
-+ DWC_FREE(container);
-+ return;
-+ }
-+
-+ container->cb = cb;
-+ container->data = data;
-+ container->wq = wq;
-+ tv.tv_sec = time / 1000;
-+ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
-+ container->hz = tvtohz(&tv);
-+ wq->container = container;
-+
-+ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
-+ workqueue_enqueue(wq->taskq, &container->task);
-+}
-+
-+int DWC_WORKQ_PENDING(dwc_workq_t *wq)
-+{
-+ return wq->pending;
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_crypto.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_crypto.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_crypto.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_crypto.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,308 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
-+ * $Revision: #5 $
-+ * $Date: 2010/09/28 $
-+ * $Change: 1596182 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+
-+/** @file
-+ * This file contains the WUSB cryptographic routines.
-+ */
-+
-+#ifdef DWC_CRYPTOLIB
-+
-+#include "dwc_crypto.h"
-+#include "usb.h"
-+
-+#ifdef DEBUG
-+static inline void dump_bytes(char *name, uint8_t *bytes, int len)
-+{
-+ int i;
-+ DWC_PRINTF("%s: ", name);
-+ for (i=0; i<len; i++) {
-+ DWC_PRINTF("%02x ", bytes[i]);
-+ }
-+ DWC_PRINTF("\n");
-+}
-+#else
-+#define dump_bytes(x...)
-+#endif
-+
-+/* Display a block */
-+void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
-+{
-+#ifdef DWC_DEBUG_CRYPTO
-+ int i, blksize = 16;
-+
-+ DWC_DEBUG("%s", prefix);
-+
-+ if (suffix == NULL) {
-+ suffix = "\n";
-+ blksize = a;
-+ }
-+
-+ for (i = 0; i < blksize; i++)
-+ DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
-+ DWC_PRINT(suffix);
-+#endif
-+}
-+
-+/**
-+ * Encrypts an array of bytes using the AES encryption engine.
-+ * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
-+ * in-place.
-+ *
-+ * @return 0 on success, negative error code on error.
-+ */
-+int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
-+{
-+ u8 block_t[16];
-+ DWC_MEMSET(block_t, 0, 16);
-+
-+ return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
-+}
-+
-+/**
-+ * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
-+ * This function takes a data string and returns the encrypted CBC
-+ * Counter-mode MIC.
-+ *
-+ * @param key The 128-bit symmetric key.
-+ * @param nonce The CCM nonce.
-+ * @param label The unique 14-byte ASCII text label.
-+ * @param bytes The byte array to be encrypted.
-+ * @param len Length of the byte array.
-+ * @param result Byte array to receive the 8-byte encrypted MIC.
-+ */
-+void dwc_wusb_cmf(u8 *key, u8 *nonce,
-+ char *label, u8 *bytes, int len, u8 *result)
-+{
-+ u8 block_m[16];
-+ u8 block_x[16];
-+ u8 block_t[8];
-+ int idx, blkNum;
-+ u16 la = (u16)(len + 14);
-+
-+ /* Set the AES-128 key */
-+ //dwc_aes_setkey(tfm, key, 16);
-+
-+ /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
-+ block_m[0] = 0x59;
-+ for (idx = 0; idx < 13; idx++)
-+ block_m[idx + 1] = nonce[idx];
-+ block_m[14] = 0;
-+ block_m[15] = 0;
-+
-+ /* Produce the CBC IV */
-+ dwc_wusb_aes_encrypt(block_m, key, block_x);
-+ show_block(block_m, "CBC IV in: ", "\n", 0);
-+ show_block(block_x, "CBC IV out:", "\n", 0);
-+
-+ /* Fill block B1 from l(a) = Blen + 14, and A */
-+ block_x[0] ^= (u8)(la >> 8);
-+ block_x[1] ^= (u8)la;
-+ for (idx = 0; idx < 14; idx++)
-+ block_x[idx + 2] ^= label[idx];
-+ show_block(block_x, "After xor: ", "b1\n", 16);
-+
-+ dwc_wusb_aes_encrypt(block_x, key, block_x);
-+ show_block(block_x, "After AES: ", "b1\n", 16);
-+
-+ idx = 0;
-+ blkNum = 0;
-+
-+ /* Fill remaining blocks with B */
-+ while (len-- > 0) {
-+ block_x[idx] ^= *bytes++;
-+ if (++idx >= 16) {
-+ idx = 0;
-+ show_block(block_x, "After xor: ", "\n", blkNum);
-+ dwc_wusb_aes_encrypt(block_x, key, block_x);
-+ show_block(block_x, "After AES: ", "\n", blkNum);
-+ blkNum++;
-+ }
-+ }
-+
-+ /* Handle partial last block */
-+ if (idx > 0) {
-+ show_block(block_x, "After xor: ", "\n", blkNum);
-+ dwc_wusb_aes_encrypt(block_x, key, block_x);
-+ show_block(block_x, "After AES: ", "\n", blkNum);
-+ }
-+
-+ /* Save the MIC tag */
-+ DWC_MEMCPY(block_t, block_x, 8);
-+ show_block(block_t, "MIC tag : ", NULL, 8);
-+
-+ /* Fill block A0 from flags = 0x01, N, and counter = 0 */
-+ block_m[0] = 0x01;
-+ block_m[14] = 0;
-+ block_m[15] = 0;
-+
-+ /* Encrypt the counter */
-+ dwc_wusb_aes_encrypt(block_m, key, block_x);
-+ show_block(block_x, "CTR[MIC] : ", NULL, 8);
-+
-+ /* XOR with MIC tag */
-+ for (idx = 0; idx < 8; idx++) {
-+ block_t[idx] ^= block_x[idx];
-+ }
-+
-+ /* Return result to caller */
-+ DWC_MEMCPY(result, block_t, 8);
-+ show_block(result, "CCM-MIC : ", NULL, 8);
-+
-+}
-+
-+/**
-+ * The PRF function described in section 6.5 of the WUSB spec. This function
-+ * concatenates MIC values returned from dwc_cmf() to create a value of
-+ * the requested length.
-+ *
-+ * @param prf_len Length of the PRF function in bits (64, 128, or 256).
-+ * @param key, nonce, label, bytes, len Same as for dwc_cmf().
-+ * @param result Byte array to receive the result.
-+ */
-+void dwc_wusb_prf(int prf_len, u8 *key,
-+ u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
-+{
-+ int i;
-+
-+ nonce[0] = 0;
-+ for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
-+ dwc_wusb_cmf(key, nonce, label, bytes, len, result);
-+ result += 8;
-+ }
-+}
-+
-+/**
-+ * Fills in CCM Nonce per the WUSB spec.
-+ *
-+ * @param[in] haddr Host address.
-+ * @param[in] daddr Device address.
-+ * @param[in] tkid Session Key(PTK) identifier.
-+ * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
-+ */
-+void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
-+ uint8_t *nonce)
-+{
-+
-+ DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
-+
-+ DWC_MEMSET(&nonce[0], 0, 16);
-+
-+ DWC_MEMCPY(&nonce[6], tkid, 3);
-+ nonce[9] = daddr & 0xFF;
-+ nonce[10] = (daddr >> 8) & 0xFF;
-+ nonce[11] = haddr & 0xFF;
-+ nonce[12] = (haddr >> 8) & 0xFF;
-+
-+ dump_bytes("CCM nonce", nonce, 16);
-+}
-+
-+/**
-+ * Generates a 16-byte cryptographic-grade random number for the Host/Device
-+ * Nonce.
-+ */
-+void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
-+{
-+ uint8_t inonce[16];
-+ uint32_t temp[4];
-+
-+ /* Fill in the Nonce */
-+ DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
-+ inonce[9] = addr & 0xFF;
-+ inonce[10] = (addr >> 8) & 0xFF;
-+ inonce[11] = inonce[9];
-+ inonce[12] = inonce[10];
-+
-+ /* Collect "randomness samples" */
-+ DWC_RANDOM_BYTES((uint8_t *)temp, 16);
-+
-+ dwc_wusb_prf_128((uint8_t *)temp, nonce,
-+ "Random Numbers", (uint8_t *)temp, sizeof(temp),
-+ nonce);
-+}
-+
-+/**
-+ * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
-+ * WUSB spec.
-+ *
-+ * @param[in] ccm_nonce Pointer to CCM Nonce.
-+ * @param[in] mk Master Key to derive the session from
-+ * @param[in] hnonce Pointer to Host Nonce.
-+ * @param[in] dnonce Pointer to Device Nonce.
-+ * @param[out] kck Pointer to where the KCK output is to be written.
-+ * @param[out] ptk Pointer to where the PTK output is to be written.
-+ */
-+void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
-+ uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
-+{
-+ uint8_t idata[32];
-+ uint8_t odata[32];
-+
-+ dump_bytes("ck", mk, 16);
-+ dump_bytes("hnonce", hnonce, 16);
-+ dump_bytes("dnonce", dnonce, 16);
-+
-+ /* The data is the HNonce and DNonce concatenated */
-+ DWC_MEMCPY(&idata[0], hnonce, 16);
-+ DWC_MEMCPY(&idata[16], dnonce, 16);
-+
-+ dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
-+
-+ /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
-+ DWC_MEMCPY(kck, &odata[0], 16);
-+ DWC_MEMCPY(ptk, &odata[16], 16);
-+
-+ dump_bytes("kck", kck, 16);
-+ dump_bytes("ptk", ptk, 16);
-+}
-+
-+/**
-+ * Generates the Message Integrity Code over the Handshake data per the
-+ * WUSB spec.
-+ *
-+ * @param ccm_nonce Pointer to CCM Nonce.
-+ * @param kck Pointer to Key Confirmation Key.
-+ * @param data Pointer to Handshake data to be checked.
-+ * @param mic Pointer to where the MIC output is to be written.
-+ */
-+void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
-+ uint8_t *data, uint8_t *mic)
-+{
-+
-+ dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
-+ data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
-+}
-+
-+#endif /* DWC_CRYPTOLIB */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_crypto.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_crypto.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_crypto.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_crypto.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,111 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
-+ * $Revision: #3 $
-+ * $Date: 2010/09/28 $
-+ * $Change: 1596182 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+
-+#ifndef _DWC_CRYPTO_H_
-+#define _DWC_CRYPTO_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** @file
-+ *
-+ * This file contains declarations for the WUSB Cryptographic routines as
-+ * defined in the WUSB spec. They are only to be used internally by the DWC UWB
-+ * modules.
-+ */
-+
-+#include "dwc_os.h"
-+
-+int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
-+
-+void dwc_wusb_cmf(u8 *key, u8 *nonce,
-+ char *label, u8 *bytes, int len, u8 *result);
-+void dwc_wusb_prf(int prf_len, u8 *key,
-+ u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
-+
-+/**
-+ * The PRF-64 function described in section 6.5 of the WUSB spec.
-+ *
-+ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
-+ */
-+static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
-+ char *label, u8 *bytes, int len, u8 *result)
-+{
-+ dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
-+}
-+
-+/**
-+ * The PRF-128 function described in section 6.5 of the WUSB spec.
-+ *
-+ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
-+ */
-+static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
-+ char *label, u8 *bytes, int len, u8 *result)
-+{
-+ dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
-+}
-+
-+/**
-+ * The PRF-256 function described in section 6.5 of the WUSB spec.
-+ *
-+ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
-+ */
-+static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
-+ char *label, u8 *bytes, int len, u8 *result)
-+{
-+ dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
-+}
-+
-+
-+void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
-+ uint8_t *nonce);
-+void dwc_wusb_gen_nonce(uint16_t addr,
-+ uint8_t *nonce);
-+
-+void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
-+ uint8_t *hnonce, uint8_t *dnonce,
-+ uint8_t *kck, uint8_t *ptk);
-+
-+
-+void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
-+ *kck, uint8_t *data, uint8_t *mic);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _DWC_CRYPTO_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_dh.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_dh.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_dh.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_dh.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,291 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
-+ * $Revision: #3 $
-+ * $Date: 2010/09/28 $
-+ * $Change: 1596182 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+#ifdef DWC_CRYPTOLIB
-+
-+#ifndef CONFIG_MACH_IPMATE
-+
-+#include "dwc_dh.h"
-+#include "dwc_modpow.h"
-+
-+#ifdef DEBUG
-+/* This function prints out a buffer in the format described in the Association
-+ * Model specification. */
-+static void dh_dump(char *str, void *_num, int len)
-+{
-+ uint8_t *num = _num;
-+ int i;
-+ DWC_PRINTF("%s\n", str);
-+ for (i = 0; i < len; i ++) {
-+ DWC_PRINTF("%02x", num[i]);
-+ if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
-+ if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
-+ }
-+
-+ DWC_PRINTF("\n");
-+}
-+#else
-+#define dh_dump(_x...) do {; } while(0)
-+#endif
-+
-+/* Constant g value */
-+static __u32 dh_g[] = {
-+ 0x02000000,
-+};
-+
-+/* Constant p value */
-+static __u32 dh_p[] = {
-+ 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
-+ 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
-+ 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
-+ 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
-+ 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
-+ 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
-+ 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
-+ 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
-+ 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
-+ 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
-+ 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
-+ 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
-+};
-+
-+static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
-+{
-+ uint8_t *in = _in;
-+ uint8_t *out = _out;
-+ int i;
-+ for (i=0; i<len; i++) {
-+ out[i] = in[len-1-i];
-+ }
-+}
-+
-+/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
-+ * big endian numbers of size len, in bytes. Each len value must be a multiple
-+ * of 4. */
-+int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
-+ void *exp, uint32_t exp_len,
-+ void *mod, uint32_t mod_len,
-+ void *out)
-+{
-+ /* modpow() takes little endian numbers. AM uses big-endian. This
-+ * function swaps bytes of numbers before passing onto modpow. */
-+
-+ int retval = 0;
-+ uint32_t *result;
-+
-+ uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
-+ uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
-+ uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
-+
-+ dh_swap_bytes(num, &bignum_num[1], num_len);
-+ bignum_num[0] = num_len / 4;
-+
-+ dh_swap_bytes(exp, &bignum_exp[1], exp_len);
-+ bignum_exp[0] = exp_len / 4;
-+
-+ dh_swap_bytes(mod, &bignum_mod[1], mod_len);
-+ bignum_mod[0] = mod_len / 4;
-+
-+ result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
-+ if (!result) {
-+ retval = -1;
-+ goto dh_modpow_nomem;
-+ }
-+
-+ dh_swap_bytes(&result[1], out, result[0] * 4);
-+ dwc_free(mem_ctx, result);
-+
-+ dh_modpow_nomem:
-+ dwc_free(mem_ctx, bignum_num);
-+ dwc_free(mem_ctx, bignum_exp);
-+ dwc_free(mem_ctx, bignum_mod);
-+ return retval;
-+}
-+
-+
-+int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
-+{
-+ int retval;
-+ uint8_t m3[385];
-+
-+#ifndef DH_TEST_VECTORS
-+ DWC_RANDOM_BYTES(exp, 32);
-+#endif
-+
-+ /* Compute the pkd */
-+ if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
-+ exp, 32,
-+ dh_p, 384, pk))) {
-+ return retval;
-+ }
-+
-+ m3[384] = nd;
-+ DWC_MEMCPY(&m3[0], pk, 384);
-+ DWC_SHA256(m3, 385, hash);
-+
-+ dh_dump("PK", pk, 384);
-+ dh_dump("SHA-256(M3)", hash, 32);
-+ return 0;
-+}
-+
-+int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
-+ uint8_t *exp, int is_host,
-+ char *dd, uint8_t *ck, uint8_t *kdk)
-+{
-+ int retval;
-+ uint8_t mv[784];
-+ uint8_t sha_result[32];
-+ uint8_t dhkey[384];
-+ uint8_t shared_secret[384];
-+ char *message;
-+ uint32_t vd;
-+
-+ uint8_t *pk;
-+
-+ if (is_host) {
-+ pk = pkd;
-+ }
-+ else {
-+ pk = pkh;
-+ }
-+
-+ if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
-+ exp, 32,
-+ dh_p, 384, shared_secret))) {
-+ return retval;
-+ }
-+ dh_dump("Shared Secret", shared_secret, 384);
-+
-+ DWC_SHA256(shared_secret, 384, dhkey);
-+ dh_dump("DHKEY", dhkey, 384);
-+
-+ DWC_MEMCPY(&mv[0], pkd, 384);
-+ DWC_MEMCPY(&mv[384], pkh, 384);
-+ DWC_MEMCPY(&mv[768], "displayed digest", 16);
-+ dh_dump("MV", mv, 784);
-+
-+ DWC_SHA256(mv, 784, sha_result);
-+ dh_dump("SHA-256(MV)", sha_result, 32);
-+ dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
-+
-+ dh_swap_bytes(sha_result, &vd, 4);
-+#ifdef DEBUG
-+ DWC_PRINTF("Vd (decimal) = %d\n", vd);
-+#endif
-+
-+ switch (nd) {
-+ case 2:
-+ vd = vd % 100;
-+ DWC_SPRINTF(dd, "%02d", vd);
-+ break;
-+ case 3:
-+ vd = vd % 1000;
-+ DWC_SPRINTF(dd, "%03d", vd);
-+ break;
-+ case 4:
-+ vd = vd % 10000;
-+ DWC_SPRINTF(dd, "%04d", vd);
-+ break;
-+ }
-+#ifdef DEBUG
-+ DWC_PRINTF("Display Digits: %s\n", dd);
-+#endif
-+
-+ message = "connection key";
-+ DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
-+ dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
-+ DWC_MEMCPY(ck, sha_result, 16);
-+
-+ message = "key derivation key";
-+ DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
-+ dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
-+ DWC_MEMCPY(kdk, sha_result, 32);
-+
-+ return 0;
-+}
-+
-+
-+#ifdef DH_TEST_VECTORS
-+
-+static __u8 dh_a[] = {
-+ 0x44, 0x00, 0x51, 0xd6,
-+ 0xf0, 0xb5, 0x5e, 0xa9,
-+ 0x67, 0xab, 0x31, 0xc6,
-+ 0x8a, 0x8b, 0x5e, 0x37,
-+ 0xd9, 0x10, 0xda, 0xe0,
-+ 0xe2, 0xd4, 0x59, 0xa4,
-+ 0x86, 0x45, 0x9c, 0xaa,
-+ 0xdf, 0x36, 0x75, 0x16,
-+};
-+
-+static __u8 dh_b[] = {
-+ 0x5d, 0xae, 0xc7, 0x86,
-+ 0x79, 0x80, 0xa3, 0x24,
-+ 0x8c, 0xe3, 0x57, 0x8f,
-+ 0xc7, 0x5f, 0x1b, 0x0f,
-+ 0x2d, 0xf8, 0x9d, 0x30,
-+ 0x6f, 0xa4, 0x52, 0xcd,
-+ 0xe0, 0x7a, 0x04, 0x8a,
-+ 0xde, 0xd9, 0x26, 0x56,
-+};
-+
-+void dwc_run_dh_test_vectors(void *mem_ctx)
-+{
-+ uint8_t pkd[384];
-+ uint8_t pkh[384];
-+ uint8_t hashd[32];
-+ uint8_t hashh[32];
-+ uint8_t ck[16];
-+ uint8_t kdk[32];
-+ char dd[5];
-+
-+ DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
-+
-+ /* compute the PKd and SHA-256(PKd || Nd) */
-+ DWC_PRINTF("Computing PKd\n");
-+ dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
-+
-+ /* compute the PKd and SHA-256(PKh || Nd) */
-+ DWC_PRINTF("Computing PKh\n");
-+ dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
-+
-+ /* compute the dhkey */
-+ dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
-+}
-+#endif /* DH_TEST_VECTORS */
-+
-+#endif /* !CONFIG_MACH_IPMATE */
-+
-+#endif /* DWC_CRYPTOLIB */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_dh.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_dh.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_dh.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_dh.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,106 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
-+ * $Revision: #4 $
-+ * $Date: 2010/09/28 $
-+ * $Change: 1596182 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+#ifndef _DWC_DH_H_
-+#define _DWC_DH_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include "dwc_os.h"
-+
-+/** @file
-+ *
-+ * This file defines the common functions on device and host for performing
-+ * numeric association as defined in the WUSB spec. They are only to be
-+ * used internally by the DWC UWB modules. */
-+
-+extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
-+extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
-+ uint8_t *key, uint32_t keylen,
-+ uint8_t *out);
-+extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
-+ void *exp, uint32_t exp_len,
-+ void *mod, uint32_t mod_len,
-+ void *out);
-+
-+/** Computes PKD or PKH, and SHA-256(PKd || Nd)
-+ *
-+ * PK = g^exp mod p.
-+ *
-+ * Input:
-+ * Nd = Number of digits on the device.
-+ *
-+ * Output:
-+ * exp = A 32-byte buffer to be filled with a randomly generated number.
-+ * used as either A or B.
-+ * pk = A 384-byte buffer to be filled with the PKH or PKD.
-+ * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
-+ */
-+extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
-+
-+/** Computes the DHKEY, and VD.
-+ *
-+ * If called from host, then it will comput DHKEY=PKD^exp % p.
-+ * If called from device, then it will comput DHKEY=PKH^exp % p.
-+ *
-+ * Input:
-+ * pkd = The PKD value.
-+ * pkh = The PKH value.
-+ * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
-+ * is_host = Set to non zero if a WUSB host is calling this function.
-+ *
-+ * Output:
-+
-+ * dd = A pointer to an buffer to be set to the displayed digits string to be shown
-+ * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
-+ * null termination character. This buffer can be used directly for display.
-+ * ck = A 16-byte buffer to be filled with the CK.
-+ * kdk = A 32-byte buffer to be filled with the KDK.
-+ */
-+extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
-+ uint8_t *exp, int is_host,
-+ char *dd, uint8_t *ck, uint8_t *kdk);
-+
-+#ifdef DH_TEST_VECTORS
-+extern void dwc_run_dh_test_vectors(void);
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _DWC_DH_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_list.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_list.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_list.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_list.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,594 @@
-+/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
-+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
-+
-+/*
-+ * Copyright (c) 1991, 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.
-+ *
-+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
-+ */
-+
-+#ifndef _DWC_LIST_H_
-+#define _DWC_LIST_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** @file
-+ *
-+ * This file defines linked list operations. It is derived from BSD with
-+ * only the MACRO names being prefixed with DWC_. This is because a few of
-+ * these names conflict with those on Linux. For documentation on use, see the
-+ * inline comments in the source code. The original license for this source
-+ * code applies and is preserved in the dwc_list.h source file.
-+ */
-+
-+/*
-+ * This file defines five types of data structures: singly-linked lists,
-+ * lists, simple queues, tail queues, and circular queues.
-+ *
-+ *
-+ * A singly-linked list is headed by a single forward pointer. The elements
-+ * are singly linked for minimum space and pointer manipulation overhead at
-+ * the expense of O(n) removal for arbitrary elements. New elements can be
-+ * added to the list after an existing element or at the head of the list.
-+ * Elements being removed from the head of the list should use the explicit
-+ * macro for this purpose for optimum efficiency. A singly-linked list may
-+ * only be traversed in the forward direction. Singly-linked lists are ideal
-+ * for applications with large datasets and few or no removals or for
-+ * implementing a LIFO queue.
-+ *
-+ * A list is headed by a single forward pointer (or an array of forward
-+ * pointers for a hash table header). The elements are doubly linked
-+ * so that an arbitrary element can be removed without a need to
-+ * traverse the list. New elements can be added to the list before
-+ * or after an existing element or at the head of the list. A list
-+ * may only be traversed in the forward direction.
-+ *
-+ * A simple queue is headed by a pair of pointers, one the head of the
-+ * list and the other to the tail of the list. The elements are singly
-+ * linked to save space, so elements can only be removed from the
-+ * head of the list. New elements can be added to the list before or after
-+ * an existing element, at the head of the list, or at the end of the
-+ * list. A simple queue may only be traversed in the forward direction.
-+ *
-+ * A tail queue is headed by a pair of pointers, one to the head of the
-+ * list and the other to the tail of the list. The elements are doubly
-+ * linked so that an arbitrary element can be removed without a need to
-+ * traverse the list. New elements can be added to the list before or
-+ * after an existing element, at the head of the list, or at the end of
-+ * the list. A tail queue may be traversed in either direction.
-+ *
-+ * A circle queue is headed by a pair of pointers, one to the head of the
-+ * list and the other to the tail of the list. The elements are doubly
-+ * linked so that an arbitrary element can be removed without a need to
-+ * traverse the list. New elements can be added to the list before or after
-+ * an existing element, at the head of the list, or at the end of the list.
-+ * A circle queue may be traversed in either direction, but has a more
-+ * complex end of list detection.
-+ *
-+ * For details on the use of these macros, see the queue(3) manual page.
-+ */
-+
-+/*
-+ * Double-linked List.
-+ */
-+
-+typedef struct dwc_list_link {
-+ struct dwc_list_link *next;
-+ struct dwc_list_link *prev;
-+} dwc_list_link_t;
-+
-+#define DWC_LIST_INIT(link) do { \
-+ (link)->next = (link); \
-+ (link)->prev = (link); \
-+} while (0)
-+
-+#define DWC_LIST_FIRST(link) ((link)->next)
-+#define DWC_LIST_LAST(link) ((link)->prev)
-+#define DWC_LIST_END(link) (link)
-+#define DWC_LIST_NEXT(link) ((link)->next)
-+#define DWC_LIST_PREV(link) ((link)->prev)
-+#define DWC_LIST_EMPTY(link) \
-+ (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
-+#define DWC_LIST_ENTRY(link, type, field) \
-+ (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
-+
-+#if 0
-+#define DWC_LIST_INSERT_HEAD(list, link) do { \
-+ (link)->next = (list)->next; \
-+ (link)->prev = (list); \
-+ (list)->next->prev = (link); \
-+ (list)->next = (link); \
-+} while (0)
-+
-+#define DWC_LIST_INSERT_TAIL(list, link) do { \
-+ (link)->next = (list); \
-+ (link)->prev = (list)->prev; \
-+ (list)->prev->next = (link); \
-+ (list)->prev = (link); \
-+} while (0)
-+#else
-+#define DWC_LIST_INSERT_HEAD(list, link) do { \
-+ dwc_list_link_t *__next__ = (list)->next; \
-+ __next__->prev = (link); \
-+ (link)->next = __next__; \
-+ (link)->prev = (list); \
-+ (list)->next = (link); \
-+} while (0)
-+
-+#define DWC_LIST_INSERT_TAIL(list, link) do { \
-+ dwc_list_link_t *__prev__ = (list)->prev; \
-+ (list)->prev = (link); \
-+ (link)->next = (list); \
-+ (link)->prev = __prev__; \
-+ __prev__->next = (link); \
-+} while (0)
-+#endif
-+
-+#if 0
-+static inline void __list_add(struct list_head *new,
-+ struct list_head *prev,
-+ struct list_head *next)
-+{
-+ next->prev = new;
-+ new->next = next;
-+ new->prev = prev;
-+ prev->next = new;
-+}
-+
-+static inline void list_add(struct list_head *new, struct list_head *head)
-+{
-+ __list_add(new, head, head->next);
-+}
-+
-+static inline void list_add_tail(struct list_head *new, struct list_head *head)
-+{
-+ __list_add(new, head->prev, head);
-+}
-+
-+static inline void __list_del(struct list_head * prev, struct list_head * next)
-+{
-+ next->prev = prev;
-+ prev->next = next;
-+}
-+
-+static inline void list_del(struct list_head *entry)
-+{
-+ __list_del(entry->prev, entry->next);
-+ entry->next = LIST_POISON1;
-+ entry->prev = LIST_POISON2;
-+}
-+#endif
-+
-+#define DWC_LIST_REMOVE(link) do { \
-+ (link)->next->prev = (link)->prev; \
-+ (link)->prev->next = (link)->next; \
-+} while (0)
-+
-+#define DWC_LIST_REMOVE_INIT(link) do { \
-+ DWC_LIST_REMOVE(link); \
-+ DWC_LIST_INIT(link); \
-+} while (0)
-+
-+#define DWC_LIST_MOVE_HEAD(list, link) do { \
-+ DWC_LIST_REMOVE(link); \
-+ DWC_LIST_INSERT_HEAD(list, link); \
-+} while (0)
-+
-+#define DWC_LIST_MOVE_TAIL(list, link) do { \
-+ DWC_LIST_REMOVE(link); \
-+ DWC_LIST_INSERT_TAIL(list, link); \
-+} while (0)
-+
-+#define DWC_LIST_FOREACH(var, list) \
-+ for((var) = DWC_LIST_FIRST(list); \
-+ (var) != DWC_LIST_END(list); \
-+ (var) = DWC_LIST_NEXT(var))
-+
-+#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
-+ for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
-+ (var) != DWC_LIST_END(list); \
-+ (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
-+
-+#define DWC_LIST_FOREACH_REVERSE(var, list) \
-+ for((var) = DWC_LIST_LAST(list); \
-+ (var) != DWC_LIST_END(list); \
-+ (var) = DWC_LIST_PREV(var))
-+
-+/*
-+ * Singly-linked List definitions.
-+ */
-+#define DWC_SLIST_HEAD(name, type) \
-+struct name { \
-+ struct type *slh_first; /* first element */ \
-+}
-+
-+#define DWC_SLIST_HEAD_INITIALIZER(head) \
-+ { NULL }
-+
-+#define DWC_SLIST_ENTRY(type) \
-+struct { \
-+ struct type *sle_next; /* next element */ \
-+}
-+
-+/*
-+ * Singly-linked List access methods.
-+ */
-+#define DWC_SLIST_FIRST(head) ((head)->slh_first)
-+#define DWC_SLIST_END(head) NULL
-+#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
-+#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
-+
-+#define DWC_SLIST_FOREACH(var, head, field) \
-+ for((var) = SLIST_FIRST(head); \
-+ (var) != SLIST_END(head); \
-+ (var) = SLIST_NEXT(var, field))
-+
-+#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
-+ for((varp) = &SLIST_FIRST((head)); \
-+ ((var) = *(varp)) != SLIST_END(head); \
-+ (varp) = &SLIST_NEXT((var), field))
-+
-+/*
-+ * Singly-linked List functions.
-+ */
-+#define DWC_SLIST_INIT(head) { \
-+ SLIST_FIRST(head) = SLIST_END(head); \
-+}
-+
-+#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
-+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
-+ (slistelm)->field.sle_next = (elm); \
-+} while (0)
-+
-+#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
-+ (elm)->field.sle_next = (head)->slh_first; \
-+ (head)->slh_first = (elm); \
-+} while (0)
-+
-+#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
-+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
-+} while (0)
-+
-+#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
-+ (head)->slh_first = (head)->slh_first->field.sle_next; \
-+} while (0)
-+
-+#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
-+ if ((head)->slh_first == (elm)) { \
-+ SLIST_REMOVE_HEAD((head), field); \
-+ } \
-+ else { \
-+ struct type *curelm = (head)->slh_first; \
-+ while( curelm->field.sle_next != (elm) ) \
-+ curelm = curelm->field.sle_next; \
-+ curelm->field.sle_next = \
-+ curelm->field.sle_next->field.sle_next; \
-+ } \
-+} while (0)
-+
-+/*
-+ * Simple queue definitions.
-+ */
-+#define DWC_SIMPLEQ_HEAD(name, type) \
-+struct name { \
-+ struct type *sqh_first; /* first element */ \
-+ struct type **sqh_last; /* addr of last next element */ \
-+}
-+
-+#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
-+ { NULL, &(head).sqh_first }
-+
-+#define DWC_SIMPLEQ_ENTRY(type) \
-+struct { \
-+ struct type *sqe_next; /* next element */ \
-+}
-+
-+/*
-+ * Simple queue access methods.
-+ */
-+#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
-+#define DWC_SIMPLEQ_END(head) NULL
-+#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
-+#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
-+
-+#define DWC_SIMPLEQ_FOREACH(var, head, field) \
-+ for((var) = SIMPLEQ_FIRST(head); \
-+ (var) != SIMPLEQ_END(head); \
-+ (var) = SIMPLEQ_NEXT(var, field))
-+
-+/*
-+ * Simple queue functions.
-+ */
-+#define DWC_SIMPLEQ_INIT(head) do { \
-+ (head)->sqh_first = NULL; \
-+ (head)->sqh_last = &(head)->sqh_first; \
-+} while (0)
-+
-+#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
-+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
-+ (head)->sqh_last = &(elm)->field.sqe_next; \
-+ (head)->sqh_first = (elm); \
-+} while (0)
-+
-+#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
-+ (elm)->field.sqe_next = NULL; \
-+ *(head)->sqh_last = (elm); \
-+ (head)->sqh_last = &(elm)->field.sqe_next; \
-+} while (0)
-+
-+#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
-+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
-+ (head)->sqh_last = &(elm)->field.sqe_next; \
-+ (listelm)->field.sqe_next = (elm); \
-+} while (0)
-+
-+#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
-+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
-+ (head)->sqh_last = &(head)->sqh_first; \
-+} while (0)
-+
-+/*
-+ * Tail queue definitions.
-+ */
-+#define DWC_TAILQ_HEAD(name, type) \
-+struct name { \
-+ struct type *tqh_first; /* first element */ \
-+ struct type **tqh_last; /* addr of last next element */ \
-+}
-+
-+#define DWC_TAILQ_HEAD_INITIALIZER(head) \
-+ { NULL, &(head).tqh_first }
-+
-+#define DWC_TAILQ_ENTRY(type) \
-+struct { \
-+ struct type *tqe_next; /* next element */ \
-+ struct type **tqe_prev; /* address of previous next element */ \
-+}
-+
-+/*
-+ * tail queue access methods
-+ */
-+#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
-+#define DWC_TAILQ_END(head) NULL
-+#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-+#define DWC_TAILQ_LAST(head, headname) \
-+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
-+/* XXX */
-+#define DWC_TAILQ_PREV(elm, headname, field) \
-+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-+#define DWC_TAILQ_EMPTY(head) \
-+ (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))
-+
-+#define DWC_TAILQ_FOREACH(var, head, field) \
-+ for ((var) = DWC_TAILQ_FIRST(head); \
-+ (var) != DWC_TAILQ_END(head); \
-+ (var) = DWC_TAILQ_NEXT(var, field))
-+
-+#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
-+ for ((var) = DWC_TAILQ_LAST(head, headname); \
-+ (var) != DWC_TAILQ_END(head); \
-+ (var) = DWC_TAILQ_PREV(var, headname, field))
-+
-+/*
-+ * Tail queue functions.
-+ */
-+#define DWC_TAILQ_INIT(head) do { \
-+ (head)->tqh_first = NULL; \
-+ (head)->tqh_last = &(head)->tqh_first; \
-+} while (0)
-+
-+#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
-+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
-+ (head)->tqh_first->field.tqe_prev = \
-+ &(elm)->field.tqe_next; \
-+ else \
-+ (head)->tqh_last = &(elm)->field.tqe_next; \
-+ (head)->tqh_first = (elm); \
-+ (elm)->field.tqe_prev = &(head)->tqh_first; \
-+} while (0)
-+
-+#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
-+ (elm)->field.tqe_next = NULL; \
-+ (elm)->field.tqe_prev = (head)->tqh_last; \
-+ *(head)->tqh_last = (elm); \
-+ (head)->tqh_last = &(elm)->field.tqe_next; \
-+} while (0)
-+
-+#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
-+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
-+ (elm)->field.tqe_next->field.tqe_prev = \
-+ &(elm)->field.tqe_next; \
-+ else \
-+ (head)->tqh_last = &(elm)->field.tqe_next; \
-+ (listelm)->field.tqe_next = (elm); \
-+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
-+} while (0)
-+
-+#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
-+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
-+ (elm)->field.tqe_next = (listelm); \
-+ *(listelm)->field.tqe_prev = (elm); \
-+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
-+} while (0)
-+
-+#define DWC_TAILQ_REMOVE(head, elm, field) do { \
-+ if (((elm)->field.tqe_next) != NULL) \
-+ (elm)->field.tqe_next->field.tqe_prev = \
-+ (elm)->field.tqe_prev; \
-+ else \
-+ (head)->tqh_last = (elm)->field.tqe_prev; \
-+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
-+} while (0)
-+
-+#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
-+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
-+ (elm2)->field.tqe_next->field.tqe_prev = \
-+ &(elm2)->field.tqe_next; \
-+ else \
-+ (head)->tqh_last = &(elm2)->field.tqe_next; \
-+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
-+ *(elm2)->field.tqe_prev = (elm2); \
-+} while (0)
-+
-+/*
-+ * Circular queue definitions.
-+ */
-+#define DWC_CIRCLEQ_HEAD(name, type) \
-+struct name { \
-+ struct type *cqh_first; /* first element */ \
-+ struct type *cqh_last; /* last element */ \
-+}
-+
-+#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
-+ { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
-+
-+#define DWC_CIRCLEQ_ENTRY(type) \
-+struct { \
-+ struct type *cqe_next; /* next element */ \
-+ struct type *cqe_prev; /* previous element */ \
-+}
-+
-+/*
-+ * Circular queue access methods
-+ */
-+#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
-+#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
-+#define DWC_CIRCLEQ_END(head) ((void *)(head))
-+#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
-+#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
-+#define DWC_CIRCLEQ_EMPTY(head) \
-+ (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
-+
-+#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
-+
-+#define DWC_CIRCLEQ_FOREACH(var, head, field) \
-+ for((var) = DWC_CIRCLEQ_FIRST(head); \
-+ (var) != DWC_CIRCLEQ_END(head); \
-+ (var) = DWC_CIRCLEQ_NEXT(var, field))
-+
-+#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
-+ for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
-+ (var) != DWC_CIRCLEQ_END(head); \
-+ (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
-+
-+#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
-+ for((var) = DWC_CIRCLEQ_LAST(head); \
-+ (var) != DWC_CIRCLEQ_END(head); \
-+ (var) = DWC_CIRCLEQ_PREV(var, field))
-+
-+/*
-+ * Circular queue functions.
-+ */
-+#define DWC_CIRCLEQ_INIT(head) do { \
-+ (head)->cqh_first = DWC_CIRCLEQ_END(head); \
-+ (head)->cqh_last = DWC_CIRCLEQ_END(head); \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
-+ (elm)->field.cqe_next = NULL; \
-+ (elm)->field.cqe_prev = NULL; \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
-+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
-+ (elm)->field.cqe_prev = (listelm); \
-+ if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
-+ (head)->cqh_last = (elm); \
-+ else \
-+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
-+ (listelm)->field.cqe_next = (elm); \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
-+ (elm)->field.cqe_next = (listelm); \
-+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
-+ if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
-+ (head)->cqh_first = (elm); \
-+ else \
-+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
-+ (listelm)->field.cqe_prev = (elm); \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
-+ (elm)->field.cqe_next = (head)->cqh_first; \
-+ (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
-+ if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
-+ (head)->cqh_last = (elm); \
-+ else \
-+ (head)->cqh_first->field.cqe_prev = (elm); \
-+ (head)->cqh_first = (elm); \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
-+ (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
-+ (elm)->field.cqe_prev = (head)->cqh_last; \
-+ if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
-+ (head)->cqh_first = (elm); \
-+ else \
-+ (head)->cqh_last->field.cqe_next = (elm); \
-+ (head)->cqh_last = (elm); \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
-+ if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
-+ (head)->cqh_last = (elm)->field.cqe_prev; \
-+ else \
-+ (elm)->field.cqe_next->field.cqe_prev = \
-+ (elm)->field.cqe_prev; \
-+ if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
-+ (head)->cqh_first = (elm)->field.cqe_next; \
-+ else \
-+ (elm)->field.cqe_prev->field.cqe_next = \
-+ (elm)->field.cqe_next; \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
-+ DWC_CIRCLEQ_REMOVE(head, elm, field); \
-+ DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
-+} while (0)
-+
-+#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
-+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
-+ DWC_CIRCLEQ_END(head)) \
-+ (head).cqh_last = (elm2); \
-+ else \
-+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
-+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
-+ DWC_CIRCLEQ_END(head)) \
-+ (head).cqh_first = (elm2); \
-+ else \
-+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
-+} while (0)
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _DWC_LIST_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_mem.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_mem.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_mem.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_mem.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,245 @@
-+/* Memory Debugging */
-+#ifdef DWC_DEBUG_MEMORY
-+
-+#include "dwc_os.h"
-+#include "dwc_list.h"
-+
-+struct allocation {
-+ void *addr;
-+ void *ctx;
-+ char *func;
-+ int line;
-+ uint32_t size;
-+ int dma;
-+ DWC_CIRCLEQ_ENTRY(allocation) entry;
-+};
-+
-+DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
-+
-+struct allocation_manager {
-+ void *mem_ctx;
-+ struct allocation_queue allocations;
-+
-+ /* statistics */
-+ int num;
-+ int num_freed;
-+ int num_active;
-+ uint32_t total;
-+ uint32_t cur;
-+ uint32_t max;
-+};
-+
-+static struct allocation_manager *manager = NULL;
-+
-+static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
-+ int dma)
-+{
-+ struct allocation *a;
-+
-+ DWC_ASSERT(manager != NULL, "manager not allocated");
-+
-+ a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
-+ if (!a) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
-+ if (!a->func) {
-+ __DWC_FREE(manager->mem_ctx, a);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
-+ a->addr = addr;
-+ a->ctx = ctx;
-+ a->line = line;
-+ a->size = size;
-+ a->dma = dma;
-+ DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
-+
-+ /* Update stats */
-+ manager->num++;
-+ manager->num_active++;
-+ manager->total += size;
-+ manager->cur += size;
-+
-+ if (manager->max < manager->cur) {
-+ manager->max = manager->cur;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct allocation *find_allocation(void *ctx, void *addr)
-+{
-+ struct allocation *a;
-+
-+ DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
-+ if (a->ctx == ctx && a->addr == addr) {
-+ return a;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static void free_allocation(void *ctx, void *addr, char const *func, int line)
-+{
-+ struct allocation *a = find_allocation(ctx, addr);
-+
-+ if (!a) {
-+ DWC_ASSERT(0,
-+ "Free of address %p that was never allocated or already freed %s:%d",
-+ addr, func, line);
-+ return;
-+ }
-+
-+ DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
-+
-+ manager->num_active--;
-+ manager->num_freed++;
-+ manager->cur -= a->size;
-+ __DWC_FREE(manager->mem_ctx, a->func);
-+ __DWC_FREE(manager->mem_ctx, a);
-+}
-+
-+int dwc_memory_debug_start(void *mem_ctx)
-+{
-+ DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
-+
-+ if (manager) {
-+ return -DWC_E_BUSY;
-+ }
-+
-+ manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
-+ if (!manager) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ DWC_CIRCLEQ_INIT(&manager->allocations);
-+ manager->mem_ctx = mem_ctx;
-+ manager->num = 0;
-+ manager->num_freed = 0;
-+ manager->num_active = 0;
-+ manager->total = 0;
-+ manager->cur = 0;
-+ manager->max = 0;
-+
-+ return 0;
-+}
-+
-+void dwc_memory_debug_stop(void)
-+{
-+ struct allocation *a;
-+
-+ dwc_memory_debug_report();
-+
-+ DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
-+ DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
-+ free_allocation(a->ctx, a->addr, NULL, -1);
-+ }
-+
-+ __DWC_FREE(manager->mem_ctx, manager);
-+}
-+
-+void dwc_memory_debug_report(void)
-+{
-+ struct allocation *a;
-+
-+ DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
-+ DWC_PRINTF("Num Allocations = %d\n", manager->num);
-+ DWC_PRINTF("Freed = %d\n", manager->num_freed);
-+ DWC_PRINTF("Active = %d\n", manager->num_active);
-+ DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
-+ DWC_PRINTF("Total Memory Used = %d\n", manager->total);
-+ DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
-+ DWC_PRINTF("Unfreed allocations:\n");
-+
-+ DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
-+ DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
-+ a->addr, a->size, a->func, a->line, a->dma);
-+ }
-+}
-+
-+/* The replacement functions */
-+void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
-+{
-+ void *addr = __DWC_ALLOC(mem_ctx, size);
-+
-+ if (!addr) {
-+ return NULL;
-+ }
-+
-+ if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
-+ __DWC_FREE(mem_ctx, addr);
-+ return NULL;
-+ }
-+
-+ return addr;
-+}
-+
-+void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
-+ int line)
-+{
-+ void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
-+
-+ if (!addr) {
-+ return NULL;
-+ }
-+
-+ if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
-+ __DWC_FREE(mem_ctx, addr);
-+ return NULL;
-+ }
-+
-+ return addr;
-+}
-+
-+void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
-+{
-+ free_allocation(mem_ctx, addr, func, line);
-+ __DWC_FREE(mem_ctx, addr);
-+}
-+
-+void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
-+ char const *func, int line)
-+{
-+ void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
-+
-+ if (!addr) {
-+ return NULL;
-+ }
-+
-+ if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
-+ __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
-+ return NULL;
-+ }
-+
-+ return addr;
-+}
-+
-+void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
-+ dwc_dma_t *dma_addr, char const *func, int line)
-+{
-+ void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
-+
-+ if (!addr) {
-+ return NULL;
-+ }
-+
-+ if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
-+ __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
-+ return NULL;
-+ }
-+
-+ return addr;
-+}
-+
-+void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
-+ dwc_dma_t dma_addr, char const *func, int line)
-+{
-+ free_allocation(dma_ctx, virt_addr, func, line);
-+ __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
-+}
-+
-+#endif /* DWC_DEBUG_MEMORY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_modpow.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_modpow.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_modpow.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_modpow.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,636 @@
-+/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
-+ *
-+ * PuTTY is copyright 1997-2007 Simon Tatham.
-+ *
-+ * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
-+ * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
-+ * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
-+ * Kuhn, and CORE SDI S.A.
-+ *
-+ * Permission is hereby granted, free of charge, to any person
-+ * obtaining a copy of this software and associated documentation files
-+ * (the "Software"), to deal in the Software without restriction,
-+ * including without limitation the rights to use, copy, modify, merge,
-+ * publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so,
-+ * subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be
-+ * included in all copies or substantial portions of the Software.
-+
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-+ * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
-+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ *
-+ */
-+#ifdef DWC_CRYPTOLIB
-+
-+#ifndef CONFIG_MACH_IPMATE
-+
-+#include "dwc_modpow.h"
-+
-+#define BIGNUM_INT_MASK 0xFFFFFFFFUL
-+#define BIGNUM_TOP_BIT 0x80000000UL
-+#define BIGNUM_INT_BITS 32
-+
-+
-+static void *snmalloc(void *mem_ctx, size_t n, size_t size)
-+{
-+ void *p;
-+ size *= n;
-+ if (size == 0) size = 1;
-+ p = dwc_alloc(mem_ctx, size);
-+ return p;
-+}
-+
-+#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
-+#define sfree dwc_free
-+
-+/*
-+ * Usage notes:
-+ * * Do not call the DIVMOD_WORD macro with expressions such as array
-+ * subscripts, as some implementations object to this (see below).
-+ * * Note that none of the division methods below will cope if the
-+ * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
-+ * to avoid this case.
-+ * If this condition occurs, in the case of the x86 DIV instruction,
-+ * an overflow exception will occur, which (according to a correspondent)
-+ * will manifest on Windows as something like
-+ * 0xC0000095: Integer overflow
-+ * The C variant won't give the right answer, either.
-+ */
-+
-+#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
-+
-+#if defined __GNUC__ && defined __i386__
-+#define DIVMOD_WORD(q, r, hi, lo, w) \
-+ __asm__("div %2" : \
-+ "=d" (r), "=a" (q) : \
-+ "r" (w), "d" (hi), "a" (lo))
-+#else
-+#define DIVMOD_WORD(q, r, hi, lo, w) do { \
-+ BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
-+ q = n / w; \
-+ r = n % w; \
-+} while (0)
-+#endif
-+
-+// q = n / w;
-+// r = n % w;
-+
-+#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
-+
-+#define BIGNUM_INTERNAL
-+
-+static Bignum newbn(void *mem_ctx, int length)
-+{
-+ Bignum b = snewn(mem_ctx, length + 1, BignumInt);
-+ //if (!b)
-+ //abort(); /* FIXME */
-+ DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
-+ b[0] = length;
-+ return b;
-+}
-+
-+void freebn(void *mem_ctx, Bignum b)
-+{
-+ /*
-+ * Burn the evidence, just in case.
-+ */
-+ DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
-+ sfree(mem_ctx, b);
-+}
-+
-+/*
-+ * Compute c = a * b.
-+ * Input is in the first len words of a and b.
-+ * Result is returned in the first 2*len words of c.
-+ */
-+static void internal_mul(BignumInt *a, BignumInt *b,
-+ BignumInt *c, int len)
-+{
-+ int i, j;
-+ BignumDblInt t;
-+
-+ for (j = 0; j < 2 * len; j++)
-+ c[j] = 0;
-+
-+ for (i = len - 1; i >= 0; i--) {
-+ t = 0;
-+ for (j = len - 1; j >= 0; j--) {
-+ t += MUL_WORD(a[i], (BignumDblInt) b[j]);
-+ t += (BignumDblInt) c[i + j + 1];
-+ c[i + j + 1] = (BignumInt) t;
-+ t = t >> BIGNUM_INT_BITS;
-+ }
-+ c[i] = (BignumInt) t;
-+ }
-+}
-+
-+static void internal_add_shifted(BignumInt *number,
-+ unsigned n, int shift)
-+{
-+ int word = 1 + (shift / BIGNUM_INT_BITS);
-+ int bshift = shift % BIGNUM_INT_BITS;
-+ BignumDblInt addend;
-+
-+ addend = (BignumDblInt)n << bshift;
-+
-+ while (addend) {
-+ addend += number[word];
-+ number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
-+ addend >>= BIGNUM_INT_BITS;
-+ word++;
-+ }
-+}
-+
-+/*
-+ * Compute a = a % m.
-+ * Input in first alen words of a and first mlen words of m.
-+ * Output in first alen words of a
-+ * (of which first alen-mlen words will be zero).
-+ * The MSW of m MUST have its high bit set.
-+ * Quotient is accumulated in the `quotient' array, which is a Bignum
-+ * rather than the internal bigendian format. Quotient parts are shifted
-+ * left by `qshift' before adding into quot.
-+ */
-+static void internal_mod(BignumInt *a, int alen,
-+ BignumInt *m, int mlen,
-+ BignumInt *quot, int qshift)
-+{
-+ BignumInt m0, m1;
-+ unsigned int h;
-+ int i, k;
-+
-+ m0 = m[0];
-+ if (mlen > 1)
-+ m1 = m[1];
-+ else
-+ m1 = 0;
-+
-+ for (i = 0; i <= alen - mlen; i++) {
-+ BignumDblInt t;
-+ unsigned int q, r, c, ai1;
-+
-+ if (i == 0) {
-+ h = 0;
-+ } else {
-+ h = a[i - 1];
-+ a[i - 1] = 0;
-+ }
-+
-+ if (i == alen - 1)
-+ ai1 = 0;
-+ else
-+ ai1 = a[i + 1];
-+
-+ /* Find q = h:a[i] / m0 */
-+ if (h >= m0) {
-+ /*
-+ * Special case.
-+ *
-+ * To illustrate it, suppose a BignumInt is 8 bits, and
-+ * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
-+ * our initial division will be 0xA123 / 0xA1, which
-+ * will give a quotient of 0x100 and a divide overflow.
-+ * However, the invariants in this division algorithm
-+ * are not violated, since the full number A1:23:... is
-+ * _less_ than the quotient prefix A1:B2:... and so the
-+ * following correction loop would have sorted it out.
-+ *
-+ * In this situation we set q to be the largest
-+ * quotient we _can_ stomach (0xFF, of course).
-+ */
-+ q = BIGNUM_INT_MASK;
-+ } else {
-+ /* Macro doesn't want an array subscript expression passed
-+ * into it (see definition), so use a temporary. */
-+ BignumInt tmplo = a[i];
-+ DIVMOD_WORD(q, r, h, tmplo, m0);
-+
-+ /* Refine our estimate of q by looking at
-+ h:a[i]:a[i+1] / m0:m1 */
-+ t = MUL_WORD(m1, q);
-+ if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
-+ q--;
-+ t -= m1;
-+ r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
-+ if (r >= (BignumDblInt) m0 &&
-+ t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
-+ }
-+ }
-+
-+ /* Subtract q * m from a[i...] */
-+ c = 0;
-+ for (k = mlen - 1; k >= 0; k--) {
-+ t = MUL_WORD(q, m[k]);
-+ t += c;
-+ c = (unsigned)(t >> BIGNUM_INT_BITS);
-+ if ((BignumInt) t > a[i + k])
-+ c++;
-+ a[i + k] -= (BignumInt) t;
-+ }
-+
-+ /* Add back m in case of borrow */
-+ if (c != h) {
-+ t = 0;
-+ for (k = mlen - 1; k >= 0; k--) {
-+ t += m[k];
-+ t += a[i + k];
-+ a[i + k] = (BignumInt) t;
-+ t = t >> BIGNUM_INT_BITS;
-+ }
-+ q--;
-+ }
-+ if (quot)
-+ internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
-+ }
-+}
-+
-+/*
-+ * Compute p % mod.
-+ * The most significant word of mod MUST be non-zero.
-+ * We assume that the result array is the same size as the mod array.
-+ * We optionally write out a quotient if `quotient' is non-NULL.
-+ * We can avoid writing out the result if `result' is NULL.
-+ */
-+void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
-+{
-+ BignumInt *n, *m;
-+ int mshift;
-+ int plen, mlen, i, j;
-+
-+ /* Allocate m of size mlen, copy mod to m */
-+ /* We use big endian internally */
-+ mlen = mod[0];
-+ m = snewn(mem_ctx, mlen, BignumInt);
-+ //if (!m)
-+ //abort(); /* FIXME */
-+ for (j = 0; j < mlen; j++)
-+ m[j] = mod[mod[0] - j];
-+
-+ /* Shift m left to make msb bit set */
-+ for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
-+ if ((m[0] << mshift) & BIGNUM_TOP_BIT)
-+ break;
-+ if (mshift) {
-+ for (i = 0; i < mlen - 1; i++)
-+ m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
-+ m[mlen - 1] = m[mlen - 1] << mshift;
-+ }
-+
-+ plen = p[0];
-+ /* Ensure plen > mlen */
-+ if (plen <= mlen)
-+ plen = mlen + 1;
-+
-+ /* Allocate n of size plen, copy p to n */
-+ n = snewn(mem_ctx, plen, BignumInt);
-+ //if (!n)
-+ //abort(); /* FIXME */
-+ for (j = 0; j < plen; j++)
-+ n[j] = 0;
-+ for (j = 1; j <= (int)p[0]; j++)
-+ n[plen - j] = p[j];
-+
-+ /* Main computation */
-+ internal_mod(n, plen, m, mlen, quotient, mshift);
-+
-+ /* Fixup result in case the modulus was shifted */
-+ if (mshift) {
-+ for (i = plen - mlen - 1; i < plen - 1; i++)
-+ n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
-+ n[plen - 1] = n[plen - 1] << mshift;
-+ internal_mod(n, plen, m, mlen, quotient, 0);
-+ for (i = plen - 1; i >= plen - mlen; i--)
-+ n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
-+ }
-+
-+ /* Copy result to buffer */
-+ if (result) {
-+ for (i = 1; i <= (int)result[0]; i++) {
-+ int j = plen - i;
-+ result[i] = j >= 0 ? n[j] : 0;
-+ }
-+ }
-+
-+ /* Free temporary arrays */
-+ for (i = 0; i < mlen; i++)
-+ m[i] = 0;
-+ sfree(mem_ctx, m);
-+ for (i = 0; i < plen; i++)
-+ n[i] = 0;
-+ sfree(mem_ctx, n);
-+}
-+
-+/*
-+ * Simple remainder.
-+ */
-+Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
-+{
-+ Bignum r = newbn(mem_ctx, b[0]);
-+ bigdivmod(mem_ctx, a, b, r, NULL);
-+ return r;
-+}
-+
-+/*
-+ * Compute (base ^ exp) % mod.
-+ */
-+Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
-+{
-+ BignumInt *a, *b, *n, *m;
-+ int mshift;
-+ int mlen, i, j;
-+ Bignum base, result;
-+
-+ /*
-+ * The most significant word of mod needs to be non-zero. It
-+ * should already be, but let's make sure.
-+ */
-+ //assert(mod[mod[0]] != 0);
-+
-+ /*
-+ * Make sure the base is smaller than the modulus, by reducing
-+ * it modulo the modulus if not.
-+ */
-+ base = bigmod(mem_ctx, base_in, mod);
-+
-+ /* Allocate m of size mlen, copy mod to m */
-+ /* We use big endian internally */
-+ mlen = mod[0];
-+ m = snewn(mem_ctx, mlen, BignumInt);
-+ //if (!m)
-+ //abort(); /* FIXME */
-+ for (j = 0; j < mlen; j++)
-+ m[j] = mod[mod[0] - j];
-+
-+ /* Shift m left to make msb bit set */
-+ for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
-+ if ((m[0] << mshift) & BIGNUM_TOP_BIT)
-+ break;
-+ if (mshift) {
-+ for (i = 0; i < mlen - 1; i++)
-+ m[i] =
-+ (m[i] << mshift) | (m[i + 1] >>
-+ (BIGNUM_INT_BITS - mshift));
-+ m[mlen - 1] = m[mlen - 1] << mshift;
-+ }
-+
-+ /* Allocate n of size mlen, copy base to n */
-+ n = snewn(mem_ctx, mlen, BignumInt);
-+ //if (!n)
-+ //abort(); /* FIXME */
-+ i = mlen - base[0];
-+ for (j = 0; j < i; j++)
-+ n[j] = 0;
-+ for (j = 0; j < base[0]; j++)
-+ n[i + j] = base[base[0] - j];
-+
-+ /* Allocate a and b of size 2*mlen. Set a = 1 */
-+ a = snewn(mem_ctx, 2 * mlen, BignumInt);
-+ //if (!a)
-+ //abort(); /* FIXME */
-+ b = snewn(mem_ctx, 2 * mlen, BignumInt);
-+ //if (!b)
-+ //abort(); /* FIXME */
-+ for (i = 0; i < 2 * mlen; i++)
-+ a[i] = 0;
-+ a[2 * mlen - 1] = 1;
-+
-+ /* Skip leading zero bits of exp. */
-+ i = 0;
-+ j = BIGNUM_INT_BITS - 1;
-+ while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
-+ j--;
-+ if (j < 0) {
-+ i++;
-+ j = BIGNUM_INT_BITS - 1;
-+ }
-+ }
-+
-+ /* Main computation */
-+ while (i < exp[0]) {
-+ while (j >= 0) {
-+ internal_mul(a + mlen, a + mlen, b, mlen);
-+ internal_mod(b, mlen * 2, m, mlen, NULL, 0);
-+ if ((exp[exp[0] - i] & (1 << j)) != 0) {
-+ internal_mul(b + mlen, n, a, mlen);
-+ internal_mod(a, mlen * 2, m, mlen, NULL, 0);
-+ } else {
-+ BignumInt *t;
-+ t = a;
-+ a = b;
-+ b = t;
-+ }
-+ j--;
-+ }
-+ i++;
-+ j = BIGNUM_INT_BITS - 1;
-+ }
-+
-+ /* Fixup result in case the modulus was shifted */
-+ if (mshift) {
-+ for (i = mlen - 1; i < 2 * mlen - 1; i++)
-+ a[i] =
-+ (a[i] << mshift) | (a[i + 1] >>
-+ (BIGNUM_INT_BITS - mshift));
-+ a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
-+ internal_mod(a, mlen * 2, m, mlen, NULL, 0);
-+ for (i = 2 * mlen - 1; i >= mlen; i--)
-+ a[i] =
-+ (a[i] >> mshift) | (a[i - 1] <<
-+ (BIGNUM_INT_BITS - mshift));
-+ }
-+
-+ /* Copy result to buffer */
-+ result = newbn(mem_ctx, mod[0]);
-+ for (i = 0; i < mlen; i++)
-+ result[result[0] - i] = a[i + mlen];
-+ while (result[0] > 1 && result[result[0]] == 0)
-+ result[0]--;
-+
-+ /* Free temporary arrays */
-+ for (i = 0; i < 2 * mlen; i++)
-+ a[i] = 0;
-+ sfree(mem_ctx, a);
-+ for (i = 0; i < 2 * mlen; i++)
-+ b[i] = 0;
-+ sfree(mem_ctx, b);
-+ for (i = 0; i < mlen; i++)
-+ m[i] = 0;
-+ sfree(mem_ctx, m);
-+ for (i = 0; i < mlen; i++)
-+ n[i] = 0;
-+ sfree(mem_ctx, n);
-+
-+ freebn(mem_ctx, base);
-+
-+ return result;
-+}
-+
-+
-+#ifdef UNITTEST
-+
-+static __u32 dh_p[] = {
-+ 96,
-+ 0xFFFFFFFF,
-+ 0xFFFFFFFF,
-+ 0xA93AD2CA,
-+ 0x4B82D120,
-+ 0xE0FD108E,
-+ 0x43DB5BFC,
-+ 0x74E5AB31,
-+ 0x08E24FA0,
-+ 0xBAD946E2,
-+ 0x770988C0,
-+ 0x7A615D6C,
-+ 0xBBE11757,
-+ 0x177B200C,
-+ 0x521F2B18,
-+ 0x3EC86A64,
-+ 0xD8760273,
-+ 0xD98A0864,
-+ 0xF12FFA06,
-+ 0x1AD2EE6B,
-+ 0xCEE3D226,
-+ 0x4A25619D,
-+ 0x1E8C94E0,
-+ 0xDB0933D7,
-+ 0xABF5AE8C,
-+ 0xA6E1E4C7,
-+ 0xB3970F85,
-+ 0x5D060C7D,
-+ 0x8AEA7157,
-+ 0x58DBEF0A,
-+ 0xECFB8504,
-+ 0xDF1CBA64,
-+ 0xA85521AB,
-+ 0x04507A33,
-+ 0xAD33170D,
-+ 0x8AAAC42D,
-+ 0x15728E5A,
-+ 0x98FA0510,
-+ 0x15D22618,
-+ 0xEA956AE5,
-+ 0x3995497C,
-+ 0x95581718,
-+ 0xDE2BCBF6,
-+ 0x6F4C52C9,
-+ 0xB5C55DF0,
-+ 0xEC07A28F,
-+ 0x9B2783A2,
-+ 0x180E8603,
-+ 0xE39E772C,
-+ 0x2E36CE3B,
-+ 0x32905E46,
-+ 0xCA18217C,
-+ 0xF1746C08,
-+ 0x4ABC9804,
-+ 0x670C354E,
-+ 0x7096966D,
-+ 0x9ED52907,
-+ 0x208552BB,
-+ 0x1C62F356,
-+ 0xDCA3AD96,
-+ 0x83655D23,
-+ 0xFD24CF5F,
-+ 0x69163FA8,
-+ 0x1C55D39A,
-+ 0x98DA4836,
-+ 0xA163BF05,
-+ 0xC2007CB8,
-+ 0xECE45B3D,
-+ 0x49286651,
-+ 0x7C4B1FE6,
-+ 0xAE9F2411,
-+ 0x5A899FA5,
-+ 0xEE386BFB,
-+ 0xF406B7ED,
-+ 0x0BFF5CB6,
-+ 0xA637ED6B,
-+ 0xF44C42E9,
-+ 0x625E7EC6,
-+ 0xE485B576,
-+ 0x6D51C245,
-+ 0x4FE1356D,
-+ 0xF25F1437,
-+ 0x302B0A6D,
-+ 0xCD3A431B,
-+ 0xEF9519B3,
-+ 0x8E3404DD,
-+ 0x514A0879,
-+ 0x3B139B22,
-+ 0x020BBEA6,
-+ 0x8A67CC74,
-+ 0x29024E08,
-+ 0x80DC1CD1,
-+ 0xC4C6628B,
-+ 0x2168C234,
-+ 0xC90FDAA2,
-+ 0xFFFFFFFF,
-+ 0xFFFFFFFF,
-+};
-+
-+static __u32 dh_a[] = {
-+ 8,
-+ 0xdf367516,
-+ 0x86459caa,
-+ 0xe2d459a4,
-+ 0xd910dae0,
-+ 0x8a8b5e37,
-+ 0x67ab31c6,
-+ 0xf0b55ea9,
-+ 0x440051d6,
-+};
-+
-+static __u32 dh_b[] = {
-+ 8,
-+ 0xded92656,
-+ 0xe07a048a,
-+ 0x6fa452cd,
-+ 0x2df89d30,
-+ 0xc75f1b0f,
-+ 0x8ce3578f,
-+ 0x7980a324,
-+ 0x5daec786,
-+};
-+
-+static __u32 dh_g[] = {
-+ 1,
-+ 2,
-+};
-+
-+int main(void)
-+{
-+ int i;
-+ __u32 *k;
-+ k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
-+
-+ printf("\n\n");
-+ for (i=0; i<k[0]; i++) {
-+ __u32 word32 = k[k[0] - i];
-+ __u16 l = word32 & 0xffff;
-+ __u16 m = (word32 & 0xffff0000) >> 16;
-+ printf("%04x %04x ", m, l);
-+ if (!((i + 1)%13)) printf("\n");
-+ }
-+ printf("\n\n");
-+
-+ if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
-+ printf("PASS\n\n");
-+ }
-+ else {
-+ printf("FAIL\n\n");
-+ }
-+
-+}
-+
-+#endif /* UNITTEST */
-+
-+#endif /* CONFIG_MACH_IPMATE */
-+
-+#endif /*DWC_CRYPTOLIB */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_modpow.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_modpow.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_modpow.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_modpow.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,34 @@
-+/*
-+ * dwc_modpow.h
-+ * See dwc_modpow.c for license and changes
-+ */
-+#ifndef _DWC_MODPOW_H
-+#define _DWC_MODPOW_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include "dwc_os.h"
-+
-+/** @file
-+ *
-+ * This file defines the module exponentiation function which is only used
-+ * internally by the DWC UWB modules for calculation of PKs during numeric
-+ * association. The routine is taken from the PUTTY, an open source terminal
-+ * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
-+ *
-+ */
-+
-+typedef uint32_t BignumInt;
-+typedef uint64_t BignumDblInt;
-+typedef BignumInt *Bignum;
-+
-+/* Compute modular exponentiaion */
-+extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _LINUX_BIGNUM_H */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_notifier.c linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_notifier.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_notifier.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_notifier.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,319 @@
-+#ifdef DWC_NOTIFYLIB
-+
-+#include "dwc_notifier.h"
-+#include "dwc_list.h"
-+
-+typedef struct dwc_observer {
-+ void *observer;
-+ dwc_notifier_callback_t callback;
-+ void *data;
-+ char *notification;
-+ DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
-+} observer_t;
-+
-+DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
-+
-+typedef struct dwc_notifier {
-+ void *mem_ctx;
-+ void *object;
-+ struct observer_queue observers;
-+ DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
-+} notifier_t;
-+
-+DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
-+
-+typedef struct manager {
-+ void *mem_ctx;
-+ void *wkq_ctx;
-+ dwc_workq_t *wq;
-+// dwc_mutex_t *mutex;
-+ struct notifier_queue notifiers;
-+} manager_t;
-+
-+static manager_t *manager = NULL;
-+
-+static int create_manager(void *mem_ctx, void *wkq_ctx)
-+{
-+ manager = dwc_alloc(mem_ctx, sizeof(manager_t));
-+ if (!manager) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ DWC_CIRCLEQ_INIT(&manager->notifiers);
-+
-+ manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
-+ if (!manager->wq) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ return 0;
-+}
-+
-+static void free_manager(void)
-+{
-+ dwc_workq_free(manager->wq);
-+
-+ /* All notifiers must have unregistered themselves before this module
-+ * can be removed. Hitting this assertion indicates a programmer
-+ * error. */
-+ DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
-+ "Notification manager being freed before all notifiers have been removed");
-+ dwc_free(manager->mem_ctx, manager);
-+}
-+
-+#ifdef DEBUG
-+static void dump_manager(void)
-+{
-+ notifier_t *n;
-+ observer_t *o;
-+
-+ DWC_ASSERT(manager, "Notification manager not found");
-+
-+ DWC_DEBUG("List of all notifiers and observers:\n");
-+ DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
-+ DWC_DEBUG("Notifier %p has observers:\n", n->object);
-+ DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
-+ DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
-+ }
-+ }
-+}
-+#else
-+#define dump_manager(...)
-+#endif
-+
-+static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
-+ dwc_notifier_callback_t callback, void *data)
-+{
-+ observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
-+
-+ if (!new_observer) {
-+ return NULL;
-+ }
-+
-+ DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
-+ new_observer->observer = observer;
-+ new_observer->notification = notification;
-+ new_observer->callback = callback;
-+ new_observer->data = data;
-+ return new_observer;
-+}
-+
-+static void free_observer(void *mem_ctx, observer_t *observer)
-+{
-+ dwc_free(mem_ctx, observer);
-+}
-+
-+static notifier_t *alloc_notifier(void *mem_ctx, void *object)
-+{
-+ notifier_t *notifier;
-+
-+ if (!object) {
-+ return NULL;
-+ }
-+
-+ notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
-+ if (!notifier) {
-+ return NULL;
-+ }
-+
-+ DWC_CIRCLEQ_INIT(&notifier->observers);
-+ DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
-+
-+ notifier->mem_ctx = mem_ctx;
-+ notifier->object = object;
-+ return notifier;
-+}
-+
-+static void free_notifier(notifier_t *notifier)
-+{
-+ observer_t *observer;
-+
-+ DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
-+ free_observer(notifier->mem_ctx, observer);
-+ }
-+
-+ dwc_free(notifier->mem_ctx, notifier);
-+}
-+
-+static notifier_t *find_notifier(void *object)
-+{
-+ notifier_t *notifier;
-+
-+ DWC_ASSERT(manager, "Notification manager not found");
-+
-+ if (!object) {
-+ return NULL;
-+ }
-+
-+ DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
-+ if (notifier->object == object) {
-+ return notifier;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
-+{
-+ return create_manager(mem_ctx, wkq_ctx);
-+}
-+
-+void dwc_free_notification_manager(void)
-+{
-+ free_manager();
-+}
-+
-+dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
-+{
-+ notifier_t *notifier;
-+
-+ DWC_ASSERT(manager, "Notification manager not found");
-+
-+ notifier = find_notifier(object);
-+ if (notifier) {
-+ DWC_ERROR("Notifier %p is already registered\n", object);
-+ return NULL;
-+ }
-+
-+ notifier = alloc_notifier(mem_ctx, object);
-+ if (!notifier) {
-+ return NULL;
-+ }
-+
-+ DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
-+
-+ DWC_INFO("Notifier %p registered", object);
-+ dump_manager();
-+
-+ return notifier;
-+}
-+
-+void dwc_unregister_notifier(dwc_notifier_t *notifier)
-+{
-+ DWC_ASSERT(manager, "Notification manager not found");
-+
-+ if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
-+ observer_t *o;
-+
-+ DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
-+ DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
-+ DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
-+ }
-+
-+ DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
-+ "Notifier %p has active observers when removing", notifier);
-+ }
-+
-+ DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
-+ free_notifier(notifier);
-+
-+ DWC_INFO("Notifier unregistered");
-+ dump_manager();
-+}
-+
-+/* Add an observer to observe the notifier for a particular state, event, or notification. */
-+int dwc_add_observer(void *observer, void *object, char *notification,
-+ dwc_notifier_callback_t callback, void *data)
-+{
-+ notifier_t *notifier = find_notifier(object);
-+ observer_t *new_observer;
-+
-+ if (!notifier) {
-+ DWC_ERROR("Notifier %p is not found when adding observer\n", object);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
-+ if (!new_observer) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
-+
-+ DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
-+ observer, object, notification, callback, data);
-+
-+ dump_manager();
-+ return 0;
-+}
-+
-+int dwc_remove_observer(void *observer)
-+{
-+ notifier_t *n;
-+
-+ DWC_ASSERT(manager, "Notification manager not found");
-+
-+ DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
-+ observer_t *o;
-+ observer_t *o2;
-+
-+ DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
-+ if (o->observer == observer) {
-+ DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
-+ DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
-+ o->observer, n->object, o->notification);
-+ free_observer(n->mem_ctx, o);
-+ }
-+ }
-+ }
-+
-+ dump_manager();
-+ return 0;
-+}
-+
-+typedef struct callback_data {
-+ void *mem_ctx;
-+ dwc_notifier_callback_t cb;
-+ void *observer;
-+ void *data;
-+ void *object;
-+ char *notification;
-+ void *notification_data;
-+} cb_data_t;
-+
-+static void cb_task(void *data)
-+{
-+ cb_data_t *cb = (cb_data_t *)data;
-+
-+ cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
-+ dwc_free(cb->mem_ctx, cb);
-+}
-+
-+void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
-+{
-+ observer_t *o;
-+
-+ DWC_ASSERT(manager, "Notification manager not found");
-+
-+ DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
-+ int len = DWC_STRLEN(notification);
-+
-+ if (DWC_STRLEN(o->notification) != len) {
-+ continue;
-+ }
-+
-+ if (DWC_STRNCMP(o->notification, notification, len) == 0) {
-+ cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
-+
-+ if (!cb_data) {
-+ DWC_ERROR("Failed to allocate callback data\n");
-+ return;
-+ }
-+
-+ cb_data->mem_ctx = notifier->mem_ctx;
-+ cb_data->cb = o->callback;
-+ cb_data->observer = o->observer;
-+ cb_data->data = o->data;
-+ cb_data->object = notifier->object;
-+ cb_data->notification = notification;
-+ cb_data->notification_data = notification_data;
-+ DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
-+ DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
-+ "Notify callback from %p for Notification %s, to observer %p",
-+ cb_data->object, notification, cb_data->observer);
-+ }
-+ }
-+}
-+
-+#endif /* DWC_NOTIFYLIB */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_notifier.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_notifier.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_notifier.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_notifier.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,122 @@
-+
-+#ifndef __DWC_NOTIFIER_H__
-+#define __DWC_NOTIFIER_H__
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include "dwc_os.h"
-+
-+/** @file
-+ *
-+ * A simple implementation of the Observer pattern. Any "module" can
-+ * register as an observer or notifier. The notion of "module" is abstract and
-+ * can mean anything used to identify either an observer or notifier. Usually
-+ * it will be a pointer to a data structure which contains some state, ie an
-+ * object.
-+ *
-+ * Before any notifiers can be added, the global notification manager must be
-+ * brought up with dwc_alloc_notification_manager().
-+ * dwc_free_notification_manager() will bring it down and free all resources.
-+ * These would typically be called upon module load and unload. The
-+ * notification manager is a single global instance that handles all registered
-+ * observable modules and observers so this should be done only once.
-+ *
-+ * A module can be observable by using Notifications to publicize some general
-+ * information about it's state or operation. It does not care who listens, or
-+ * even if anyone listens, or what they do with the information. The observable
-+ * modules do not need to know any information about it's observers or their
-+ * interface, or their state or data.
-+ *
-+ * Any module can register to emit Notifications. It should publish a list of
-+ * notifications that it can emit and their behavior, such as when they will get
-+ * triggered, and what information will be provided to the observer. Then it
-+ * should register itself as an observable module. See dwc_register_notifier().
-+ *
-+ * Any module can observe any observable, registered module, provided it has a
-+ * handle to the other module and knows what notifications to observe. See
-+ * dwc_add_observer().
-+ *
-+ * A function of type dwc_notifier_callback_t is called whenever a notification
-+ * is triggered with one or more observers observing it. This function is
-+ * called in it's own process so it may sleep or block if needed. It is
-+ * guaranteed to be called sometime after the notification has occurred and will
-+ * be called once per each time the notification is triggered. It will NOT be
-+ * called in the same process context used to trigger the notification.
-+ *
-+ * @section Limitiations
-+ *
-+ * Keep in mind that Notifications that can be triggered in rapid sucession may
-+ * schedule too many processes too handle. Be aware of this limitation when
-+ * designing to use notifications, and only add notifications for appropriate
-+ * observable information.
-+ *
-+ * Also Notification callbacks are not synchronous. If you need to synchronize
-+ * the behavior between module/observer you must use other means. And perhaps
-+ * that will mean Notifications are not the proper solution.
-+ */
-+
-+struct dwc_notifier;
-+typedef struct dwc_notifier dwc_notifier_t;
-+
-+/** The callback function must be of this type.
-+ *
-+ * @param object This is the object that is being observed.
-+ * @param notification This is the notification that was triggered.
-+ * @param observer This is the observer
-+ * @param notification_data This is notification-specific data that the notifier
-+ * has included in this notification. The value of this should be published in
-+ * the documentation of the observable module with the notifications.
-+ * @param user_data This is any custom data that the observer provided when
-+ * adding itself as an observer to the notification. */
-+typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
-+ void *notification_data, void *user_data);
-+
-+/** Brings up the notification manager. */
-+extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
-+/** Brings down the notification manager. */
-+extern void dwc_free_notification_manager(void);
-+
-+/** This function registers an observable module. A dwc_notifier_t object is
-+ * returned to the observable module. This is an opaque object that is used by
-+ * the observable module to trigger notifications. This object should only be
-+ * accessible to functions that are authorized to trigger notifications for this
-+ * module. Observers do not need this object. */
-+extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
-+
-+/** This function unregisters an observable module. All observers have to be
-+ * removed prior to unregistration. */
-+extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
-+
-+/** Add a module as an observer to the observable module. The observable module
-+ * needs to have previously registered with the notification manager.
-+ *
-+ * @param observer The observer module
-+ * @param object The module to observe
-+ * @param notification The notification to observe
-+ * @param callback The callback function to call
-+ * @param user_data Any additional user data to pass into the callback function */
-+extern int dwc_add_observer(void *observer, void *object, char *notification,
-+ dwc_notifier_callback_t callback, void *user_data);
-+
-+/** Removes the specified observer from all notifications that it is currently
-+ * observing. */
-+extern int dwc_remove_observer(void *observer);
-+
-+/** This function triggers a Notification. It should be called by the
-+ * observable module, or any module or library which the observable module
-+ * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
-+ *
-+ * dwc_notify is a non-blocking function. Callbacks are scheduled called in
-+ * their own process context for each trigger. Callbacks can be blocking.
-+ * dwc_notify can be called from interrupt context if needed.
-+ *
-+ */
-+void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* __DWC_NOTIFIER_H__ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_os.h linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_os.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/dwc_os.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/dwc_os.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1262 @@
-+/* =========================================================================
-+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
-+ * $Revision: #14 $
-+ * $Date: 2010/11/04 $
-+ * $Change: 1621695 $
-+ *
-+ * Synopsys Portability Library Software and documentation
-+ * (hereinafter, "Software") is an Unsupported proprietary work of
-+ * Synopsys, Inc. unless otherwise expressly agreed to in writing
-+ * between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product
-+ * under any End User Software License Agreement or Agreement for
-+ * Licensed Product with Synopsys or any supplement thereto. You are
-+ * permitted to use and redistribute this Software in source and binary
-+ * forms, with or without modification, provided that redistributions
-+ * of source code must retain this notice. You may not view, use,
-+ * disclose, copy or distribute this file or any information contained
-+ * herein except pursuant to this license grant from Synopsys. If you
-+ * do not agree with this notice, including the disclaimer below, then
-+ * you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
-+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
-+ * SYNOPSYS 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.
-+ * ========================================================================= */
-+#ifndef _DWC_OS_H_
-+#define _DWC_OS_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** @file
-+ *
-+ * DWC portability library, low level os-wrapper functions
-+ *
-+ */
-+
-+/* These basic types need to be defined by some OS header file or custom header
-+ * file for your specific target architecture.
-+ *
-+ * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
-+ *
-+ * Any custom or alternate header file must be added and enabled here.
-+ */
-+
-+#ifdef DWC_LINUX
-+# include <linux/types.h>
-+# ifdef CONFIG_DEBUG_MUTEXES
-+# include <linux/mutex.h>
-+# endif
-+# include <linux/errno.h>
-+# include <stdarg.h>
-+#endif
-+
-+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+# include <os_dep.h>
-+#endif
-+
-+
-+/** @name Primitive Types and Values */
-+
-+/** We define a boolean type for consistency. Can be either YES or NO */
-+typedef uint8_t dwc_bool_t;
-+#define YES 1
-+#define NO 0
-+
-+#ifdef DWC_LINUX
-+
-+/** @name Error Codes */
-+#define DWC_E_INVALID EINVAL
-+#define DWC_E_NO_MEMORY ENOMEM
-+#define DWC_E_NO_DEVICE ENODEV
-+#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
-+#define DWC_E_TIMEOUT ETIMEDOUT
-+#define DWC_E_BUSY EBUSY
-+#define DWC_E_AGAIN EAGAIN
-+#define DWC_E_RESTART ERESTART
-+#define DWC_E_ABORT ECONNABORTED
-+#define DWC_E_SHUTDOWN ESHUTDOWN
-+#define DWC_E_NO_DATA ENODATA
-+#define DWC_E_DISCONNECT ECONNRESET
-+#define DWC_E_UNKNOWN EINVAL
-+#define DWC_E_NO_STREAM_RES ENOSR
-+#define DWC_E_COMMUNICATION ECOMM
-+#define DWC_E_OVERFLOW EOVERFLOW
-+#define DWC_E_PROTOCOL EPROTO
-+#define DWC_E_IN_PROGRESS EINPROGRESS
-+#define DWC_E_PIPE EPIPE
-+#define DWC_E_IO EIO
-+#define DWC_E_NO_SPACE ENOSPC
-+
-+#else
-+
-+/** @name Error Codes */
-+#define DWC_E_INVALID 1001
-+#define DWC_E_NO_MEMORY 1002
-+#define DWC_E_NO_DEVICE 1003
-+#define DWC_E_NOT_SUPPORTED 1004
-+#define DWC_E_TIMEOUT 1005
-+#define DWC_E_BUSY 1006
-+#define DWC_E_AGAIN 1007
-+#define DWC_E_RESTART 1008
-+#define DWC_E_ABORT 1009
-+#define DWC_E_SHUTDOWN 1010
-+#define DWC_E_NO_DATA 1011
-+#define DWC_E_DISCONNECT 2000
-+#define DWC_E_UNKNOWN 3000
-+#define DWC_E_NO_STREAM_RES 4001
-+#define DWC_E_COMMUNICATION 4002
-+#define DWC_E_OVERFLOW 4003
-+#define DWC_E_PROTOCOL 4004
-+#define DWC_E_IN_PROGRESS 4005
-+#define DWC_E_PIPE 4006
-+#define DWC_E_IO 4007
-+#define DWC_E_NO_SPACE 4008
-+
-+#endif
-+
-+
-+/** @name Tracing/Logging Functions
-+ *
-+ * These function provide the capability to add tracing, debugging, and error
-+ * messages, as well exceptions as assertions. The WUDEV uses these
-+ * extensively. These could be logged to the main console, the serial port, an
-+ * internal buffer, etc. These functions could also be no-op if they are too
-+ * expensive on your system. By default undefining the DEBUG macro already
-+ * no-ops some of these functions. */
-+
-+/** Returns non-zero if in interrupt context. */
-+extern dwc_bool_t DWC_IN_IRQ(void);
-+#define dwc_in_irq DWC_IN_IRQ
-+
-+/** Returns "IRQ" if DWC_IN_IRQ is true. */
-+static inline char *dwc_irq(void) {
-+ return DWC_IN_IRQ() ? "IRQ" : "";
-+}
-+
-+/** Returns non-zero if in bottom-half context. */
-+extern dwc_bool_t DWC_IN_BH(void);
-+#define dwc_in_bh DWC_IN_BH
-+
-+/** Returns "BH" if DWC_IN_BH is true. */
-+static inline char *dwc_bh(void) {
-+ return DWC_IN_BH() ? "BH" : "";
-+}
-+
-+/**
-+ * A vprintf() clone. Just call vprintf if you've got it.
-+ */
-+extern void DWC_VPRINTF(char *format, va_list args);
-+#define dwc_vprintf DWC_VPRINTF
-+
-+/**
-+ * A vsnprintf() clone. Just call vprintf if you've got it.
-+ */
-+extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
-+#define dwc_vsnprintf DWC_VSNPRINTF
-+
-+/**
-+ * printf() clone. Just call printf if you've go it.
-+ */
-+extern void DWC_PRINTF(char *format, ...)
-+/* This provides compiler level static checking of the parameters if you're
-+ * using GCC. */
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 1, 2)));
-+#else
-+ ;
-+#endif
-+#define dwc_printf DWC_PRINTF
-+
-+/**
-+ * sprintf() clone. Just call sprintf if you've got it.
-+ */
-+extern int DWC_SPRINTF(char *string, char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 2, 3)));
-+#else
-+ ;
-+#endif
-+#define dwc_sprintf DWC_SPRINTF
-+
-+/**
-+ * snprintf() clone. Just call snprintf if you've got it.
-+ */
-+extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 3, 4)));
-+#else
-+ ;
-+#endif
-+#define dwc_snprintf DWC_SNPRINTF
-+
-+/**
-+ * Prints a WARNING message. On systems that don't differentiate between
-+ * warnings and regular log messages, just print it. Indicates that something
-+ * may be wrong with the driver. Works like printf().
-+ *
-+ * Use the DWC_WARN macro to call this function.
-+ */
-+extern void __DWC_WARN(char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 1, 2)));
-+#else
-+ ;
-+#endif
-+
-+/**
-+ * Prints an error message. On systems that don't differentiate between errors
-+ * and regular log messages, just print it. Indicates that something went wrong
-+ * with the driver. Works like printf().
-+ *
-+ * Use the DWC_ERROR macro to call this function.
-+ */
-+extern void __DWC_ERROR(char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 1, 2)));
-+#else
-+ ;
-+#endif
-+
-+/**
-+ * Prints an exception error message and takes some user-defined action such as
-+ * print out a backtrace or trigger a breakpoint. Indicates that something went
-+ * abnormally wrong with the driver such as programmer error, or other
-+ * exceptional condition. It should not be ignored so even on systems without
-+ * printing capability, some action should be taken to notify the developer of
-+ * it. Works like printf().
-+ */
-+extern void DWC_EXCEPTION(char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 1, 2)));
-+#else
-+ ;
-+#endif
-+#define dwc_exception DWC_EXCEPTION
-+
-+#ifndef DWC_OTG_DEBUG_LEV
-+#define DWC_OTG_DEBUG_LEV 0
-+#endif
-+
-+#ifdef DEBUG
-+/**
-+ * Prints out a debug message. Used for logging/trace messages.
-+ *
-+ * Use the DWC_DEBUG macro to call this function
-+ */
-+extern void __DWC_DEBUG(char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 1, 2)));
-+#else
-+ ;
-+#endif
-+#else
-+#define __DWC_DEBUG printk
-+#endif
-+
-+/**
-+ * Prints out a Debug message.
-+ */
-+#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
-+ __func__, dwc_irq(), ## _args)
-+#define dwc_debug DWC_DEBUG
-+/**
-+ * Prints out a Debug message if enabled at compile time.
-+ */
-+#if DWC_OTG_DEBUG_LEV > 0
-+#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
-+#else
-+#define DWC_DEBUGC(_format, _args...)
-+#endif
-+#define dwc_debugc DWC_DEBUGC
-+/**
-+ * Prints out an informative message.
-+ */
-+#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
-+ dwc_irq(), ## _args)
-+#define dwc_info DWC_INFO
-+/**
-+ * Prints out an informative message if enabled at compile time.
-+ */
-+#if DWC_OTG_DEBUG_LEV > 1
-+#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
-+#else
-+#define DWC_INFOC(_format, _args...)
-+#endif
-+#define dwc_infoc DWC_INFOC
-+/**
-+ * Prints out a warning message.
-+ */
-+#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
-+ dwc_irq(), __func__, __LINE__, ## _args)
-+#define dwc_warn DWC_WARN
-+/**
-+ * Prints out an error message.
-+ */
-+#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
-+ dwc_irq(), __func__, __LINE__, ## _args)
-+#define dwc_error DWC_ERROR
-+
-+#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
-+ dwc_irq(), __func__, __LINE__, ## _args)
-+#define dwc_proto_error DWC_PROTO_ERROR
-+
-+#ifdef DEBUG
-+/** Prints out a exception error message if the _expr expression fails. Disabled
-+ * if DEBUG is not enabled. */
-+#define DWC_ASSERT(_expr, _format, _args...) do { \
-+ if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
-+ __FILE__, __LINE__, ## _args); } \
-+ } while (0)
-+#else
-+#define DWC_ASSERT(_x...)
-+#endif
-+#define dwc_assert DWC_ASSERT
-+
-+
-+/** @name Byte Ordering
-+ * The following functions are for conversions between processor's byte ordering
-+ * and specific ordering you want.
-+ */
-+
-+/** Converts 32 bit data in CPU byte ordering to little endian. */
-+extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
-+#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
-+
-+/** Converts 32 bit data in CPU byte orderint to big endian. */
-+extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
-+#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
-+
-+/** Converts 32 bit little endian data to CPU byte ordering. */
-+extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
-+#define dwc_le32_to_cpu DWC_LE32_TO_CPU
-+
-+/** Converts 32 bit big endian data to CPU byte ordering. */
-+extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
-+#define dwc_be32_to_cpu DWC_BE32_TO_CPU
-+
-+/** Converts 16 bit data in CPU byte ordering to little endian. */
-+extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
-+#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
-+
-+/** Converts 16 bit data in CPU byte orderint to big endian. */
-+extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
-+#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
-+
-+/** Converts 16 bit little endian data to CPU byte ordering. */
-+extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
-+#define dwc_le16_to_cpu DWC_LE16_TO_CPU
-+
-+/** Converts 16 bit bi endian data to CPU byte ordering. */
-+extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
-+#define dwc_be16_to_cpu DWC_BE16_TO_CPU
-+
-+
-+/** @name Register Read/Write
-+ *
-+ * The following six functions should be implemented to read/write registers of
-+ * 32-bit and 64-bit sizes. All modules use this to read/write register values.
-+ * The reg value is a pointer to the register calculated from the void *base
-+ * variable passed into the driver when it is started. */
-+
-+#ifdef DWC_LINUX
-+/* Linux doesn't need any extra parameters for register read/write, so we
-+ * just throw away the IO context parameter.
-+ */
-+/** Reads the content of a 32-bit register. */
-+extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
-+#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
-+
-+/** Reads the content of a 64-bit register. */
-+extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
-+#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
-+
-+/** Writes to a 32-bit register. */
-+extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
-+#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
-+
-+/** Writes to a 64-bit register. */
-+extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
-+#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
-+
-+/**
-+ * Modify bit values in a register. Using the
-+ * algorithm: (reg_contents & ~clear_mask) | set_mask.
-+ */
-+extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
-+#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
-+extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
-+#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
-+
-+#endif /* DWC_LINUX */
-+
-+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+typedef struct dwc_ioctx {
-+ struct device *dev;
-+ bus_space_tag_t iot;
-+ bus_space_handle_t ioh;
-+} dwc_ioctx_t;
-+
-+/** BSD needs two extra parameters for register read/write, so we pass
-+ * them in using the IO context parameter.
-+ */
-+/** Reads the content of a 32-bit register. */
-+extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
-+#define dwc_read_reg32 DWC_READ_REG32
-+
-+/** Reads the content of a 64-bit register. */
-+extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
-+#define dwc_read_reg64 DWC_READ_REG64
-+
-+/** Writes to a 32-bit register. */
-+extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
-+#define dwc_write_reg32 DWC_WRITE_REG32
-+
-+/** Writes to a 64-bit register. */
-+extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
-+#define dwc_write_reg64 DWC_WRITE_REG64
-+
-+/**
-+ * Modify bit values in a register. Using the
-+ * algorithm: (reg_contents & ~clear_mask) | set_mask.
-+ */
-+extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
-+#define dwc_modify_reg32 DWC_MODIFY_REG32
-+extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
-+#define dwc_modify_reg64 DWC_MODIFY_REG64
-+
-+#endif /* DWC_FREEBSD || DWC_NETBSD */
-+
-+/** @cond */
-+
-+/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
-+ * register writes. */
-+
-+#ifdef DWC_LINUX
-+
-+# ifdef DWC_DEBUG_REGS
-+
-+#define dwc_define_read_write_reg_n(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
-+ return DWC_READ_REG32(&container->regs->_reg[num]); \
-+} \
-+static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
-+ DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
-+ &(((uint32_t*)container->regs->_reg)[num]), data); \
-+ DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
-+}
-+
-+#define dwc_define_read_write_reg(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg(_container_type *container) { \
-+ return DWC_READ_REG32(&container->regs->_reg); \
-+} \
-+static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
-+ DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
-+ DWC_WRITE_REG32(&container->regs->_reg, data); \
-+}
-+
-+# else /* DWC_DEBUG_REGS */
-+
-+#define dwc_define_read_write_reg_n(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
-+ return DWC_READ_REG32(&container->regs->_reg[num]); \
-+} \
-+static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
-+ DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
-+}
-+
-+#define dwc_define_read_write_reg(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg(_container_type *container) { \
-+ return DWC_READ_REG32(&container->regs->_reg); \
-+} \
-+static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
-+ DWC_WRITE_REG32(&container->regs->_reg, data); \
-+}
-+
-+# endif /* DWC_DEBUG_REGS */
-+
-+#endif /* DWC_LINUX */
-+
-+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+
-+# ifdef DWC_DEBUG_REGS
-+
-+#define dwc_define_read_write_reg_n(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
-+ return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
-+} \
-+static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
-+ DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
-+ &(((uint32_t*)container->regs->_reg)[num]), data); \
-+ DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
-+}
-+
-+#define dwc_define_read_write_reg(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
-+ return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
-+} \
-+static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
-+ DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
-+ DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
-+}
-+
-+# else /* DWC_DEBUG_REGS */
-+
-+#define dwc_define_read_write_reg_n(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
-+ return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
-+} \
-+static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
-+ DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
-+}
-+
-+#define dwc_define_read_write_reg(_reg,_container_type) \
-+static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
-+ return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
-+} \
-+static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
-+ DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
-+}
-+
-+# endif /* DWC_DEBUG_REGS */
-+
-+#endif /* DWC_FREEBSD || DWC_NETBSD */
-+
-+/** @endcond */
-+
-+
-+#ifdef DWC_CRYPTOLIB
-+/** @name Crypto Functions
-+ *
-+ * These are the low-level cryptographic functions used by the driver. */
-+
-+/** Perform AES CBC */
-+extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
-+#define dwc_aes_cbc DWC_AES_CBC
-+
-+/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
-+extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
-+#define dwc_random_bytes DWC_RANDOM_BYTES
-+
-+/** Perform the SHA-256 hash function */
-+extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
-+#define dwc_sha256 DWC_SHA256
-+
-+/** Calculated the HMAC-SHA256 */
-+extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
-+#define dwc_hmac_sha256 DWC_HMAC_SHA256
-+
-+#endif /* DWC_CRYPTOLIB */
-+
-+
-+/** @name Memory Allocation
-+ *
-+ * These function provide access to memory allocation. There are only 2 DMA
-+ * functions and 3 Regular memory functions that need to be implemented. None
-+ * of the memory debugging routines need to be implemented. The allocation
-+ * routines all ZERO the contents of the memory.
-+ *
-+ * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
-+ * This checks for memory leaks, keeping track of alloc/free pairs. It also
-+ * keeps track of how much memory the driver is using at any given time. */
-+
-+#define DWC_PAGE_SIZE 4096
-+#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
-+#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
-+
-+#define DWC_INVALID_DMA_ADDR 0x0
-+
-+#ifdef DWC_LINUX
-+/** Type for a DMA address */
-+typedef dma_addr_t dwc_dma_t;
-+#endif
-+
-+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+typedef bus_addr_t dwc_dma_t;
-+#endif
-+
-+#ifdef DWC_FREEBSD
-+typedef struct dwc_dmactx {
-+ struct device *dev;
-+ bus_dma_tag_t dma_tag;
-+ bus_dmamap_t dma_map;
-+ bus_addr_t dma_paddr;
-+ void *dma_vaddr;
-+} dwc_dmactx_t;
-+#endif
-+
-+#ifdef DWC_NETBSD
-+typedef struct dwc_dmactx {
-+ struct device *dev;
-+ bus_dma_tag_t dma_tag;
-+ bus_dmamap_t dma_map;
-+ bus_dma_segment_t segs[1];
-+ int nsegs;
-+ bus_addr_t dma_paddr;
-+ void *dma_vaddr;
-+} dwc_dmactx_t;
-+#endif
-+
-+/* @todo these functions will be added in the future */
-+#if 0
-+/**
-+ * Creates a DMA pool from which you can allocate DMA buffers. Buffers
-+ * allocated from this pool will be guaranteed to meet the size, alignment, and
-+ * boundary requirements specified.
-+ *
-+ * @param[in] size Specifies the size of the buffers that will be allocated from
-+ * this pool.
-+ * @param[in] align Specifies the byte alignment requirements of the buffers
-+ * allocated from this pool. Must be a power of 2.
-+ * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
-+ * this pool must not cross.
-+ *
-+ * @returns A pointer to an internal opaque structure which is not to be
-+ * accessed outside of these library functions. Use this handle to specify
-+ * which pools to allocate/free DMA buffers from and also to destroy the pool,
-+ * when you are done with it.
-+ */
-+extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
-+
-+/**
-+ * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
-+ */
-+extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
-+
-+/**
-+ * Allocate a buffer from the specified DMA pool and zeros its contents.
-+ */
-+extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
-+
-+/**
-+ * Free a previously allocated buffer from the DMA pool.
-+ */
-+extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
-+#endif
-+
-+/** Allocates a DMA capable buffer and zeroes its contents. */
-+extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
-+
-+/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
-+extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
-+
-+/** Frees a previously allocated buffer. */
-+extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
-+
-+/** Allocates a block of memory and zeroes its contents. */
-+extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
-+
-+/** Allocates a block of memory and zeroes its contents, in an atomic manner
-+ * which can be used inside interrupt context. The size should be sufficiently
-+ * small, a few KB at most, such that failures are not likely to occur. Can just call
-+ * __DWC_ALLOC if it is atomic. */
-+extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
-+
-+/** Frees a previously allocated buffer. */
-+extern void __DWC_FREE(void *mem_ctx, void *addr);
-+
-+#ifndef DWC_DEBUG_MEMORY
-+
-+#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
-+#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
-+#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
-+
-+# ifdef DWC_LINUX
-+#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
-+#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
-+#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _size_, _virt_, _dma_)
-+# endif
-+
-+# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
-+#define DWC_DMA_FREE __DWC_DMA_FREE
-+# endif
-+extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
-+
-+#else /* DWC_DEBUG_MEMORY */
-+
-+extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
-+extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
-+extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
-+extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
-+ char const *func, int line);
-+extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
-+ char const *func, int line);
-+extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
-+ dwc_dma_t dma_addr, char const *func, int line);
-+
-+extern int dwc_memory_debug_start(void *mem_ctx);
-+extern void dwc_memory_debug_stop(void);
-+extern void dwc_memory_debug_report(void);
-+
-+#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
-+#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
-+ __func__, __LINE__)
-+#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
-+
-+# ifdef DWC_LINUX
-+#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
-+ _dma_, __func__, __LINE__)
-+#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
-+ _dma_, __func__, __LINE__)
-+#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _size_, \
-+ _virt_, _dma_, __func__, __LINE__)
-+# endif
-+
-+# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
-+ _dma_, __func__, __LINE__)
-+#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
-+ _virt_, _dma_, __func__, __LINE__)
-+# endif
-+
-+#endif /* DWC_DEBUG_MEMORY */
-+
-+#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
-+#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
-+#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
-+
-+#ifdef DWC_LINUX
-+/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
-+ * just throw away the DMA context parameter.
-+ */
-+#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
-+#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
-+#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
-+#endif
-+
-+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+/** BSD needs several extra parameters for DMA buffer allocation, so we pass
-+ * them in using the DMA context parameter.
-+ */
-+#define dwc_dma_alloc DWC_DMA_ALLOC
-+#define dwc_dma_free DWC_DMA_FREE
-+#endif
-+
-+
-+/** @name Memory and String Processing */
-+
-+/** memset() clone */
-+extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
-+#define dwc_memset DWC_MEMSET
-+
-+/** memcpy() clone */
-+extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
-+#define dwc_memcpy DWC_MEMCPY
-+
-+/** memmove() clone */
-+extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
-+#define dwc_memmove DWC_MEMMOVE
-+
-+/** memcmp() clone */
-+extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
-+#define dwc_memcmp DWC_MEMCMP
-+
-+/** strcmp() clone */
-+extern int DWC_STRCMP(void *s1, void *s2);
-+#define dwc_strcmp DWC_STRCMP
-+
-+/** strncmp() clone */
-+extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
-+#define dwc_strncmp DWC_STRNCMP
-+
-+/** strlen() clone, for NULL terminated ASCII strings */
-+extern int DWC_STRLEN(char const *str);
-+#define dwc_strlen DWC_STRLEN
-+
-+/** strcpy() clone, for NULL terminated ASCII strings */
-+extern char *DWC_STRCPY(char *to, const char *from);
-+#define dwc_strcpy DWC_STRCPY
-+
-+/** strdup() clone. If you wish to use memory allocation debugging, this
-+ * implementation of strdup should use the DWC_* memory routines instead of
-+ * calling a predefined strdup. Otherwise the memory allocated by this routine
-+ * will not be seen by the debugging routines. */
-+extern char *DWC_STRDUP(char const *str);
-+#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
-+
-+/** NOT an atoi() clone. Read the description carefully. Returns an integer
-+ * converted from the string str in base 10 unless the string begins with a "0x"
-+ * in which case it is base 16. String must be a NULL terminated sequence of
-+ * ASCII characters and may optionally begin with whitespace, a + or -, and a
-+ * "0x" prefix if base 16. The remaining characters must be valid digits for
-+ * the number and end with a NULL character. If any invalid characters are
-+ * encountered or it returns with a negative error code and the results of the
-+ * conversion are undefined. On sucess it returns 0. Overflow conditions are
-+ * undefined. An example implementation using atoi() can be referenced from the
-+ * Linux implementation. */
-+extern int DWC_ATOI(const char *str, int32_t *value);
-+#define dwc_atoi DWC_ATOI
-+
-+/** Same as above but for unsigned. */
-+extern int DWC_ATOUI(const char *str, uint32_t *value);
-+#define dwc_atoui DWC_ATOUI
-+
-+#ifdef DWC_UTFLIB
-+/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
-+extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
-+#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
-+#endif
-+
-+
-+/** @name Wait queues
-+ *
-+ * Wait queues provide a means of synchronizing between threads or processes. A
-+ * process can block on a waitq if some condition is not true, waiting for it to
-+ * become true. When the waitq is triggered all waiting process will get
-+ * unblocked and the condition will be check again. Waitqs should be triggered
-+ * every time a condition can potentially change.*/
-+struct dwc_waitq;
-+
-+/** Type for a waitq */
-+typedef struct dwc_waitq dwc_waitq_t;
-+
-+/** The type of waitq condition callback function. This is called every time
-+ * condition is evaluated. */
-+typedef int (*dwc_waitq_condition_t)(void *data);
-+
-+/** Allocate a waitq */
-+extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
-+#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
-+
-+/** Free a waitq */
-+extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
-+#define dwc_waitq_free DWC_WAITQ_FREE
-+
-+/** Check the condition and if it is false, block on the waitq. When unblocked, check the
-+ * condition again. The function returns when the condition becomes true. The return value
-+ * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
-+extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
-+#define dwc_waitq_wait DWC_WAITQ_WAIT
-+
-+/** Check the condition and if it is false, block on the waitq. When unblocked,
-+ * check the condition again. The function returns when the condition become
-+ * true or the timeout has passed. The return value is 0 on condition true or
-+ * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
-+ * error. */
-+extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
-+ void *data, int32_t msecs);
-+#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
-+
-+/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
-+ * has potentially changed. */
-+extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
-+#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
-+
-+/** Unblock all processes waiting on the waitq with an ABORTED result. */
-+extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
-+#define dwc_waitq_abort DWC_WAITQ_ABORT
-+
-+
-+/** @name Threads
-+ *
-+ * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
-+ * whenever it is woken up, and then return. The DWC_THREAD_STOP function
-+ * returns the value from the thread.
-+ */
-+
-+struct dwc_thread;
-+
-+/** Type for a thread */
-+typedef struct dwc_thread dwc_thread_t;
-+
-+/** The thread function */
-+typedef int (*dwc_thread_function_t)(void *data);
-+
-+/** Create a thread and start it running the thread_function. Returns a handle
-+ * to the thread */
-+extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
-+#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
-+
-+/** Stops a thread. Return the value returned by the thread. Or will return
-+ * DWC_ABORT if the thread never started. */
-+extern int DWC_THREAD_STOP(dwc_thread_t *thread);
-+#define dwc_thread_stop DWC_THREAD_STOP
-+
-+/** Signifies to the thread that it must stop. */
-+#ifdef DWC_LINUX
-+/* Linux doesn't need any parameters for kthread_should_stop() */
-+extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
-+#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
-+
-+/* No thread_exit function in Linux */
-+#define dwc_thread_exit(_thrd_)
-+#endif
-+
-+#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
-+/** BSD needs the thread pointer for kthread_suspend_check() */
-+extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
-+#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
-+
-+/** The thread must call this to exit. */
-+extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
-+#define dwc_thread_exit DWC_THREAD_EXIT
-+#endif
-+
-+
-+/** @name Work queues
-+ *
-+ * Workqs are used to queue a callback function to be called at some later time,
-+ * in another thread. */
-+struct dwc_workq;
-+
-+/** Type for a workq */
-+typedef struct dwc_workq dwc_workq_t;
-+
-+/** The type of the callback function to be called. */
-+typedef void (*dwc_work_callback_t)(void *data);
-+
-+/** Allocate a workq */
-+extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
-+#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
-+
-+/** Free a workq. All work must be completed before being freed. */
-+extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
-+#define dwc_workq_free DWC_WORKQ_FREE
-+
-+/** Schedule a callback on the workq, passing in data. The function will be
-+ * scheduled at some later time. */
-+extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
-+ void *data, char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 4, 5)));
-+#else
-+ ;
-+#endif
-+#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
-+
-+/** Schedule a callback on the workq, that will be called until at least
-+ * given number miliseconds have passed. */
-+extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
-+ void *data, uint32_t time, char *format, ...)
-+#ifdef __GNUC__
-+ __attribute__ ((format(printf, 5, 6)));
-+#else
-+ ;
-+#endif
-+#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
-+
-+/** The number of processes in the workq */
-+extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
-+#define dwc_workq_pending DWC_WORKQ_PENDING
-+
-+/** Blocks until all the work in the workq is complete or timed out. Returns <
-+ * 0 on timeout. */
-+extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
-+#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
-+
-+
-+/** @name Tasklets
-+ *
-+ */
-+struct dwc_tasklet;
-+
-+/** Type for a tasklet */
-+typedef struct dwc_tasklet dwc_tasklet_t;
-+
-+/** The type of the callback function to be called */
-+typedef void (*dwc_tasklet_callback_t)(void *data);
-+
-+/** Allocates a tasklet */
-+extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
-+#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
-+
-+/** Frees a tasklet */
-+extern void DWC_TASK_FREE(dwc_tasklet_t *task);
-+#define dwc_task_free DWC_TASK_FREE
-+
-+/** Schedules a tasklet to run */
-+extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
-+#define dwc_task_schedule DWC_TASK_SCHEDULE
-+
-+extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task);
-+#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE
-+
-+/** @name Timer
-+ *
-+ * Callbacks must be small and atomic.
-+ */
-+struct dwc_timer;
-+
-+/** Type for a timer */
-+typedef struct dwc_timer dwc_timer_t;
-+
-+/** The type of the callback function to be called */
-+typedef void (*dwc_timer_callback_t)(void *data);
-+
-+/** Allocates a timer */
-+extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
-+#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
-+
-+/** Frees a timer */
-+extern void DWC_TIMER_FREE(dwc_timer_t *timer);
-+#define dwc_timer_free DWC_TIMER_FREE
-+
-+/** Schedules the timer to run at time ms from now. And will repeat at every
-+ * repeat_interval msec therafter
-+ *
-+ * Modifies a timer that is still awaiting execution to a new expiration time.
-+ * The mod_time is added to the old time. */
-+extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
-+#define dwc_timer_schedule DWC_TIMER_SCHEDULE
-+
-+/** Disables the timer from execution. */
-+extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
-+#define dwc_timer_cancel DWC_TIMER_CANCEL
-+
-+
-+/** @name Spinlocks
-+ *
-+ * These locks are used when the work between the lock/unlock is atomic and
-+ * short. Interrupts are also disabled during the lock/unlock and thus they are
-+ * suitable to lock between interrupt/non-interrupt context. They also lock
-+ * between processes if you have multiple CPUs or Preemption. If you don't have
-+ * multiple CPUS or Preemption, then the you can simply implement the
-+ * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
-+ * the work between the lock/unlock is atomic, the process context will never
-+ * change, and so you never have to lock between processes. */
-+
-+struct dwc_spinlock;
-+
-+/** Type for a spinlock */
-+typedef struct dwc_spinlock dwc_spinlock_t;
-+
-+/** Type for the 'flags' argument to spinlock funtions */
-+typedef unsigned long dwc_irqflags_t;
-+
-+/** Returns an initialized lock variable. This function should allocate and
-+ * initialize the OS-specific data structure used for locking. This data
-+ * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
-+ * be freed by the DWC_FREE_LOCK when it is no longer used. */
-+extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
-+#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
-+
-+/** Frees an initialized lock variable. */
-+extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
-+#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
-+
-+/** Disables interrupts and blocks until it acquires the lock.
-+ *
-+ * @param lock Pointer to the spinlock.
-+ * @param flags Unsigned long for irq flags storage.
-+ */
-+extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
-+#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
-+
-+/** Re-enables the interrupt and releases the lock.
-+ *
-+ * @param lock Pointer to the spinlock.
-+ * @param flags Unsigned long for irq flags storage. Must be the same as was
-+ * passed into DWC_LOCK.
-+ */
-+extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
-+#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
-+
-+/** Blocks until it acquires the lock.
-+ *
-+ * @param lock Pointer to the spinlock.
-+ */
-+extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
-+#define dwc_spinlock DWC_SPINLOCK
-+
-+/** Releases the lock.
-+ *
-+ * @param lock Pointer to the spinlock.
-+ */
-+extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
-+#define dwc_spinunlock DWC_SPINUNLOCK
-+
-+
-+/** @name Mutexes
-+ *
-+ * Unlike spinlocks Mutexes lock only between processes and the work between the
-+ * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
-+ */
-+
-+struct dwc_mutex;
-+
-+/** Type for a mutex */
-+typedef struct dwc_mutex dwc_mutex_t;
-+
-+/* For Linux Mutex Debugging make it inline because the debugging routines use
-+ * the symbol to determine recursive locking. This makes it falsely think
-+ * recursive locking occurs. */
-+#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
-+#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
-+ __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
-+ mutex_init((struct mutex *)__mutexp); \
-+})
-+#endif
-+
-+/** Allocate a mutex */
-+extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
-+#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
-+
-+/* For memory leak debugging when using Linux Mutex Debugging */
-+#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
-+#define DWC_MUTEX_FREE(__mutexp) do { \
-+ mutex_destroy((struct mutex *)__mutexp); \
-+ DWC_FREE(__mutexp); \
-+} while(0)
-+#else
-+/** Free a mutex */
-+extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
-+#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
-+#endif
-+
-+/** Lock a mutex */
-+extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
-+#define dwc_mutex_lock DWC_MUTEX_LOCK
-+
-+/** Non-blocking lock returns 1 on successful lock. */
-+extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
-+#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
-+
-+/** Unlock a mutex */
-+extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
-+#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
-+
-+
-+/** @name Time */
-+
-+/** Microsecond delay.
-+ *
-+ * @param usecs Microseconds to delay.
-+ */
-+extern void DWC_UDELAY(uint32_t usecs);
-+#define dwc_udelay DWC_UDELAY
-+
-+/** Millisecond delay.
-+ *
-+ * @param msecs Milliseconds to delay.
-+ */
-+extern void DWC_MDELAY(uint32_t msecs);
-+#define dwc_mdelay DWC_MDELAY
-+
-+/** Non-busy waiting.
-+ * Sleeps for specified number of milliseconds.
-+ *
-+ * @param msecs Milliseconds to sleep.
-+ */
-+extern void DWC_MSLEEP(uint32_t msecs);
-+#define dwc_msleep DWC_MSLEEP
-+
-+/**
-+ * Returns number of milliseconds since boot.
-+ */
-+extern uint32_t DWC_TIME(void);
-+#define dwc_time DWC_TIME
-+
-+
-+
-+
-+/* @mainpage DWC Portability and Common Library
-+ *
-+ * This is the documentation for the DWC Portability and Common Library.
-+ *
-+ * @section intro Introduction
-+ *
-+ * The DWC Portability library consists of wrapper calls and data structures to
-+ * all low-level functions which are typically provided by the OS. The WUDEV
-+ * driver uses only these functions. In order to port the WUDEV driver, only
-+ * the functions in this library need to be re-implemented, with the same
-+ * behavior as documented here.
-+ *
-+ * The Common library consists of higher level functions, which rely only on
-+ * calling the functions from the DWC Portability library. These common
-+ * routines are shared across modules. Some of the common libraries need to be
-+ * used directly by the driver programmer when porting WUDEV. Such as the
-+ * parameter and notification libraries.
-+ *
-+ * @section low Portability Library OS Wrapper Functions
-+ *
-+ * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
-+ * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
-+ * these functions are included in the dwc_os.h file.
-+ *
-+ * There are many functions here covering a wide array of OS services. Please
-+ * see dwc_os.h for details, and implementation notes for each function.
-+ *
-+ * @section common Common Library Functions
-+ *
-+ * Any function starting with dwc and in all lowercase is a common library
-+ * routine. These functions have a portable implementation and do not need to
-+ * be reimplemented when porting. The common routines can be used by any
-+ * driver, and some must be used by the end user to control the drivers. For
-+ * example, you must use the Parameter common library in order to set the
-+ * parameters in the WUDEV module.
-+ *
-+ * The common libraries consist of the following:
-+ *
-+ * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
-+ * - Parameters - Used internally and can be used by end-user. See dwc_params.h
-+ * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
-+ * - Lists - Used internally and can be used by end-user. See dwc_list.h
-+ * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
-+ * - Modpow - Used internally only. See dwc_modpow.h
-+ * - DH - Used internally only. See dwc_dh.h
-+ * - Crypto - Used internally only. See dwc_crypto.h
-+ *
-+ *
-+ * @section prereq Prerequistes For dwc_os.h
-+ * @subsection types Data Types
-+ *
-+ * The dwc_os.h file assumes that several low-level data types are pre defined for the
-+ * compilation environment. These data types are:
-+ *
-+ * - uint8_t - unsigned 8-bit data type
-+ * - int8_t - signed 8-bit data type
-+ * - uint16_t - unsigned 16-bit data type
-+ * - int16_t - signed 16-bit data type
-+ * - uint32_t - unsigned 32-bit data type
-+ * - int32_t - signed 32-bit data type
-+ * - uint64_t - unsigned 64-bit data type
-+ * - int64_t - signed 64-bit data type
-+ *
-+ * Ensure that these are defined before using dwc_os.h. The easiest way to do
-+ * that is to modify the top of the file to include the appropriate header.
-+ * This is already done for the Linux environment. If the DWC_LINUX macro is
-+ * defined, the correct header will be added. A standard header <stdint.h> is
-+ * also used for environments where standard C headers are available.
-+ *
-+ * @subsection stdarg Variable Arguments
-+ *
-+ * Variable arguments are provided by a standard C header <stdarg.h>. it is
-+ * available in Both the Linux and ANSI C enviornment. An equivalent must be
-+ * provided in your enviornment in order to use dwc_os.h with the debug and
-+ * tracing message functionality.
-+ *
-+ * @subsection thread Threading
-+ *
-+ * WUDEV Core must be run on an operating system that provides for multiple
-+ * threads/processes. Threading can be implemented in many ways, even in
-+ * embedded systems without an operating system. At the bare minimum, the
-+ * system should be able to start any number of processes at any time to handle
-+ * special work. It need not be a pre-emptive system. Process context can
-+ * change upon a call to a blocking function. The hardware interrupt context
-+ * that calls the module's ISR() function must be differentiable from process
-+ * context, even if your processes are impemented via a hardware interrupt.
-+ * Further locking mechanism between process must exist (or be implemented), and
-+ * process context must have a way to disable interrupts for a period of time to
-+ * lock them out. If all of this exists, the functions in dwc_os.h related to
-+ * threading should be able to be implemented with the defined behavior.
-+ *
-+ */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _DWC_OS_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/Makefile linux-3.11.10/drivers/usb/host/dwc_common_port/Makefile
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,58 @@
-+#
-+# Makefile for DWC_common library
-+#
-+
-+ifneq ($(KERNELRELEASE),)
-+
-+EXTRA_CFLAGS += -DDWC_LINUX
-+#EXTRA_CFLAGS += -DDEBUG
-+#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
-+#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
-+
-+EXTRA_CFLAGS += -DDWC_LIBMODULE
-+EXTRA_CFLAGS += -DDWC_CCLIB
-+#EXTRA_CFLAGS += -DDWC_CRYPTOLIB
-+EXTRA_CFLAGS += -DDWC_NOTIFYLIB
-+EXTRA_CFLAGS += -DDWC_UTFLIB
-+
-+obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
-+dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
-+ dwc_crypto.o dwc_notifier.o \
-+ dwc_common_linux.o dwc_mem.o
-+
-+kernrelwd := $(subst ., ,$(KERNELRELEASE))
-+kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
-+
-+ifneq ($(kernrel3),2.6.20)
-+# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually
-+EXTRA_CFLAGS += $(CPPFLAGS)
-+endif
-+
-+else
-+
-+#ifeq ($(KDIR),)
-+#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
-+#endif
-+
-+ifeq ($(ARCH),)
-+$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
-+ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
-+endif
-+
-+ifeq ($(DOXYGEN),)
-+DOXYGEN := doxygen
-+endif
-+
-+default:
-+ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
-+
-+docs: $(wildcard *.[hc]) doc/doxygen.cfg
-+ $(DOXYGEN) doc/doxygen.cfg
-+
-+tags: $(wildcard *.[hc])
-+ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
-+
-+endif
-+
-+clean:
-+ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/Makefile.fbsd linux-3.11.10/drivers/usb/host/dwc_common_port/Makefile.fbsd
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/Makefile.fbsd 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/Makefile.fbsd 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,17 @@
-+CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
-+CFLAGS += -DDWC_FREEBSD
-+CFLAGS += -DDEBUG
-+#CFLAGS += -DDWC_DEBUG_REGS
-+#CFLAGS += -DDWC_DEBUG_MEMORY
-+
-+#CFLAGS += -DDWC_LIBMODULE
-+#CFLAGS += -DDWC_CCLIB
-+#CFLAGS += -DDWC_CRYPTOLIB
-+#CFLAGS += -DDWC_NOTIFYLIB
-+#CFLAGS += -DDWC_UTFLIB
-+
-+KMOD = dwc_common_port_lib
-+SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
-+ dwc_common_fbsd.c dwc_mem.c
-+
-+.include <bsd.kmod.mk>
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/Makefile.linux linux-3.11.10/drivers/usb/host/dwc_common_port/Makefile.linux
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/Makefile.linux 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/Makefile.linux 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,49 @@
-+#
-+# Makefile for DWC_common library
-+#
-+ifneq ($(KERNELRELEASE),)
-+
-+EXTRA_CFLAGS += -DDWC_LINUX
-+#EXTRA_CFLAGS += -DDEBUG
-+#EXTRA_CFLAGS += -DDWC_DEBUG_REGS
-+#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY
-+
-+EXTRA_CFLAGS += -DDWC_LIBMODULE
-+EXTRA_CFLAGS += -DDWC_CCLIB
-+EXTRA_CFLAGS += -DDWC_CRYPTOLIB
-+EXTRA_CFLAGS += -DDWC_NOTIFYLIB
-+EXTRA_CFLAGS += -DDWC_UTFLIB
-+
-+obj-m := dwc_common_port_lib.o
-+dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
-+ dwc_crypto.o dwc_notifier.o \
-+ dwc_common_linux.o dwc_mem.o
-+
-+else
-+
-+ifeq ($(KDIR),)
-+$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
-+endif
-+
-+ifeq ($(ARCH),)
-+$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
-+ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
-+endif
-+
-+ifeq ($(DOXYGEN),)
-+DOXYGEN := doxygen
-+endif
-+
-+default:
-+ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
-+
-+docs: $(wildcard *.[hc]) doc/doxygen.cfg
-+ $(DOXYGEN) doc/doxygen.cfg
-+
-+tags: $(wildcard *.[hc])
-+ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
-+
-+endif
-+
-+clean:
-+ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_common_port/usb.h linux-3.11.10/drivers/usb/host/dwc_common_port/usb.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_common_port/usb.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_common_port/usb.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,946 @@
-+/*
-+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
-+ * All rights reserved.
-+ *
-+ * This code is derived from software contributed to The NetBSD Foundation
-+ * by Lennart Augustsson (lennart@augustsson.net) at
-+ * Carlstedt Research & Technology.
-+ *
-+ * 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. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * This product includes software developed by the NetBSD
-+ * Foundation, Inc. and its contributors.
-+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-+ */
-+
-+/* Modified by Synopsys, Inc, 12/12/2007 */
-+
-+
-+#ifndef _USB_H_
-+#define _USB_H_
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*
-+ * The USB records contain some unaligned little-endian word
-+ * components. The U[SG]ETW macros take care of both the alignment
-+ * and endian problem and should always be used to access non-byte
-+ * values.
-+ */
-+typedef u_int8_t uByte;
-+typedef u_int8_t uWord[2];
-+typedef u_int8_t uDWord[4];
-+
-+#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
-+#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
-+#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
-+ ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
-+
-+#if 1
-+#define UGETW(w) ((w)[0] | ((w)[1] << 8))
-+#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
-+#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
-+#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
-+ (w)[1] = (u_int8_t)((v) >> 8), \
-+ (w)[2] = (u_int8_t)((v) >> 16), \
-+ (w)[3] = (u_int8_t)((v) >> 24))
-+#else
-+/*
-+ * On little-endian machines that can handle unanliged accesses
-+ * (e.g. i386) these macros can be replaced by the following.
-+ */
-+#define UGETW(w) (*(u_int16_t *)(w))
-+#define USETW(w,v) (*(u_int16_t *)(w) = (v))
-+#define UGETDW(w) (*(u_int32_t *)(w))
-+#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
-+#endif
-+
-+/*
-+ * Macros for accessing UAS IU fields, which are big-endian
-+ */
-+#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
-+#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
-+#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
-+ ((x) >> 8) & 0xff, (x) & 0xff }
-+#define IUGETW(w) (((w)[0] << 8) | (w)[1])
-+#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
-+#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
-+#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
-+ (w)[1] = (u_int8_t)((v) >> 16), \
-+ (w)[2] = (u_int8_t)((v) >> 8), \
-+ (w)[3] = (u_int8_t)(v))
-+
-+#define UPACKED __attribute__((__packed__))
-+
-+typedef struct {
-+ uByte bmRequestType;
-+ uByte bRequest;
-+ uWord wValue;
-+ uWord wIndex;
-+ uWord wLength;
-+} UPACKED usb_device_request_t;
-+
-+#define UT_GET_DIR(a) ((a) & 0x80)
-+#define UT_WRITE 0x00
-+#define UT_READ 0x80
-+
-+#define UT_GET_TYPE(a) ((a) & 0x60)
-+#define UT_STANDARD 0x00
-+#define UT_CLASS 0x20
-+#define UT_VENDOR 0x40
-+
-+#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
-+#define UT_DEVICE 0x00
-+#define UT_INTERFACE 0x01
-+#define UT_ENDPOINT 0x02
-+#define UT_OTHER 0x03
-+
-+#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
-+#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
-+#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
-+#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
-+#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
-+#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
-+#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
-+#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
-+#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
-+#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
-+#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
-+#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
-+#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
-+#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
-+#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
-+#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
-+#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
-+#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
-+#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
-+#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
-+#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
-+#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
-+
-+/* Requests */
-+#define UR_GET_STATUS 0x00
-+#define USTAT_STANDARD_STATUS 0x00
-+#define WUSTAT_WUSB_FEATURE 0x01
-+#define WUSTAT_CHANNEL_INFO 0x02
-+#define WUSTAT_RECEIVED_DATA 0x03
-+#define WUSTAT_MAS_AVAILABILITY 0x04
-+#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
-+#define UR_CLEAR_FEATURE 0x01
-+#define UR_SET_FEATURE 0x03
-+#define UR_SET_AND_TEST_FEATURE 0x0c
-+#define UR_SET_ADDRESS 0x05
-+#define UR_GET_DESCRIPTOR 0x06
-+#define UDESC_DEVICE 0x01
-+#define UDESC_CONFIG 0x02
-+#define UDESC_STRING 0x03
-+#define UDESC_INTERFACE 0x04
-+#define UDESC_ENDPOINT 0x05
-+#define UDESC_SS_USB_COMPANION 0x30
-+#define UDESC_DEVICE_QUALIFIER 0x06
-+#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
-+#define UDESC_INTERFACE_POWER 0x08
-+#define UDESC_OTG 0x09
-+#define WUDESC_SECURITY 0x0c
-+#define WUDESC_KEY 0x0d
-+#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
-+#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
-+#define WUD_KEY_TYPE_ASSOC 0x01
-+#define WUD_KEY_TYPE_GTK 0x02
-+#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
-+#define WUD_KEY_ORIGIN_HOST 0x00
-+#define WUD_KEY_ORIGIN_DEVICE 0x01
-+#define WUDESC_ENCRYPTION_TYPE 0x0e
-+#define WUDESC_BOS 0x0f
-+#define WUDESC_DEVICE_CAPABILITY 0x10
-+#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
-+#define UDESC_BOS 0x0f
-+#define UDESC_DEVICE_CAPABILITY 0x10
-+#define UDESC_CS_DEVICE 0x21 /* class specific */
-+#define UDESC_CS_CONFIG 0x22
-+#define UDESC_CS_STRING 0x23
-+#define UDESC_CS_INTERFACE 0x24
-+#define UDESC_CS_ENDPOINT 0x25
-+#define UDESC_HUB 0x29
-+#define UR_SET_DESCRIPTOR 0x07
-+#define UR_GET_CONFIG 0x08
-+#define UR_SET_CONFIG 0x09
-+#define UR_GET_INTERFACE 0x0a
-+#define UR_SET_INTERFACE 0x0b
-+#define UR_SYNCH_FRAME 0x0c
-+#define WUR_SET_ENCRYPTION 0x0d
-+#define WUR_GET_ENCRYPTION 0x0e
-+#define WUR_SET_HANDSHAKE 0x0f
-+#define WUR_GET_HANDSHAKE 0x10
-+#define WUR_SET_CONNECTION 0x11
-+#define WUR_SET_SECURITY_DATA 0x12
-+#define WUR_GET_SECURITY_DATA 0x13
-+#define WUR_SET_WUSB_DATA 0x14
-+#define WUDATA_DRPIE_INFO 0x01
-+#define WUDATA_TRANSMIT_DATA 0x02
-+#define WUDATA_TRANSMIT_PARAMS 0x03
-+#define WUDATA_RECEIVE_PARAMS 0x04
-+#define WUDATA_TRANSMIT_POWER 0x05
-+#define WUR_LOOPBACK_DATA_WRITE 0x15
-+#define WUR_LOOPBACK_DATA_READ 0x16
-+#define WUR_SET_INTERFACE_DS 0x17
-+
-+/* Feature numbers */
-+#define UF_ENDPOINT_HALT 0
-+#define UF_DEVICE_REMOTE_WAKEUP 1
-+#define UF_TEST_MODE 2
-+#define UF_DEVICE_B_HNP_ENABLE 3
-+#define UF_DEVICE_A_HNP_SUPPORT 4
-+#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
-+#define WUF_WUSB 3
-+#define WUF_TX_DRPIE 0x0
-+#define WUF_DEV_XMIT_PACKET 0x1
-+#define WUF_COUNT_PACKETS 0x2
-+#define WUF_CAPTURE_PACKETS 0x3
-+#define UF_FUNCTION_SUSPEND 0
-+#define UF_U1_ENABLE 48
-+#define UF_U2_ENABLE 49
-+#define UF_LTM_ENABLE 50
-+
-+/* Class requests from the USB 2.0 hub spec, table 11-15 */
-+#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
-+#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
-+#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
-+#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
-+#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
-+#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
-+#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
-+#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
-+
-+#ifdef _MSC_VER
-+#include <pshpack1.h>
-+#endif
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bDescriptorSubtype;
-+} UPACKED usb_descriptor_t;
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+} UPACKED usb_descriptor_header_t;
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uWord bcdUSB;
-+#define UD_USB_2_0 0x0200
-+#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
-+ uByte bDeviceClass;
-+ uByte bDeviceSubClass;
-+ uByte bDeviceProtocol;
-+ uByte bMaxPacketSize;
-+ /* The fields below are not part of the initial descriptor. */
-+ uWord idVendor;
-+ uWord idProduct;
-+ uWord bcdDevice;
-+ uByte iManufacturer;
-+ uByte iProduct;
-+ uByte iSerialNumber;
-+ uByte bNumConfigurations;
-+} UPACKED usb_device_descriptor_t;
-+#define USB_DEVICE_DESCRIPTOR_SIZE 18
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uWord wTotalLength;
-+ uByte bNumInterface;
-+ uByte bConfigurationValue;
-+ uByte iConfiguration;
-+#define UC_ATT_ONE (1 << 7) /* must be set */
-+#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
-+#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
-+#define UC_ATT_BATTERY (1 << 4) /* battery powered */
-+ uByte bmAttributes;
-+#define UC_BUS_POWERED 0x80
-+#define UC_SELF_POWERED 0x40
-+#define UC_REMOTE_WAKEUP 0x20
-+ uByte bMaxPower; /* max current in 2 mA units */
-+#define UC_POWER_FACTOR 2
-+} UPACKED usb_config_descriptor_t;
-+#define USB_CONFIG_DESCRIPTOR_SIZE 9
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bInterfaceNumber;
-+ uByte bAlternateSetting;
-+ uByte bNumEndpoints;
-+ uByte bInterfaceClass;
-+ uByte bInterfaceSubClass;
-+ uByte bInterfaceProtocol;
-+ uByte iInterface;
-+} UPACKED usb_interface_descriptor_t;
-+#define USB_INTERFACE_DESCRIPTOR_SIZE 9
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bEndpointAddress;
-+#define UE_GET_DIR(a) ((a) & 0x80)
-+#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
-+#define UE_DIR_IN 0x80
-+#define UE_DIR_OUT 0x00
-+#define UE_ADDR 0x0f
-+#define UE_GET_ADDR(a) ((a) & UE_ADDR)
-+ uByte bmAttributes;
-+#define UE_XFERTYPE 0x03
-+#define UE_CONTROL 0x00
-+#define UE_ISOCHRONOUS 0x01
-+#define UE_BULK 0x02
-+#define UE_INTERRUPT 0x03
-+#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
-+#define UE_ISO_TYPE 0x0c
-+#define UE_ISO_ASYNC 0x04
-+#define UE_ISO_ADAPT 0x08
-+#define UE_ISO_SYNC 0x0c
-+#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
-+ uWord wMaxPacketSize;
-+ uByte bInterval;
-+} UPACKED usb_endpoint_descriptor_t;
-+#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
-+
-+typedef struct ss_endpoint_companion_descriptor {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bMaxBurst;
-+#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
-+#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
-+#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
-+#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
-+ uByte bmAttributes;
-+ uWord wBytesPerInterval;
-+} UPACKED ss_endpoint_companion_descriptor_t;
-+#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uWord bString[127];
-+} UPACKED usb_string_descriptor_t;
-+#define USB_MAX_STRING_LEN 128
-+#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
-+
-+/* Hub specific request */
-+#define UR_GET_BUS_STATE 0x02
-+#define UR_CLEAR_TT_BUFFER 0x08
-+#define UR_RESET_TT 0x09
-+#define UR_GET_TT_STATE 0x0a
-+#define UR_STOP_TT 0x0b
-+
-+/* Hub features */
-+#define UHF_C_HUB_LOCAL_POWER 0
-+#define UHF_C_HUB_OVER_CURRENT 1
-+#define UHF_PORT_CONNECTION 0
-+#define UHF_PORT_ENABLE 1
-+#define UHF_PORT_SUSPEND 2
-+#define UHF_PORT_OVER_CURRENT 3
-+#define UHF_PORT_RESET 4
-+#define UHF_PORT_L1 5
-+#define UHF_PORT_POWER 8
-+#define UHF_PORT_LOW_SPEED 9
-+#define UHF_PORT_HIGH_SPEED 10
-+#define UHF_C_PORT_CONNECTION 16
-+#define UHF_C_PORT_ENABLE 17
-+#define UHF_C_PORT_SUSPEND 18
-+#define UHF_C_PORT_OVER_CURRENT 19
-+#define UHF_C_PORT_RESET 20
-+#define UHF_C_PORT_L1 23
-+#define UHF_PORT_TEST 21
-+#define UHF_PORT_INDICATOR 22
-+
-+typedef struct {
-+ uByte bDescLength;
-+ uByte bDescriptorType;
-+ uByte bNbrPorts;
-+ uWord wHubCharacteristics;
-+#define UHD_PWR 0x0003
-+#define UHD_PWR_GANGED 0x0000
-+#define UHD_PWR_INDIVIDUAL 0x0001
-+#define UHD_PWR_NO_SWITCH 0x0002
-+#define UHD_COMPOUND 0x0004
-+#define UHD_OC 0x0018
-+#define UHD_OC_GLOBAL 0x0000
-+#define UHD_OC_INDIVIDUAL 0x0008
-+#define UHD_OC_NONE 0x0010
-+#define UHD_TT_THINK 0x0060
-+#define UHD_TT_THINK_8 0x0000
-+#define UHD_TT_THINK_16 0x0020
-+#define UHD_TT_THINK_24 0x0040
-+#define UHD_TT_THINK_32 0x0060
-+#define UHD_PORT_IND 0x0080
-+ uByte bPwrOn2PwrGood; /* delay in 2 ms units */
-+#define UHD_PWRON_FACTOR 2
-+ uByte bHubContrCurrent;
-+ uByte DeviceRemovable[32]; /* max 255 ports */
-+#define UHD_NOT_REMOV(desc, i) \
-+ (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
-+ /* deprecated */ uByte PortPowerCtrlMask[1];
-+} UPACKED usb_hub_descriptor_t;
-+#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uWord bcdUSB;
-+ uByte bDeviceClass;
-+ uByte bDeviceSubClass;
-+ uByte bDeviceProtocol;
-+ uByte bMaxPacketSize0;
-+ uByte bNumConfigurations;
-+ uByte bReserved;
-+} UPACKED usb_device_qualifier_t;
-+#define USB_DEVICE_QUALIFIER_SIZE 10
-+
-+typedef struct {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bmAttributes;
-+#define UOTG_SRP 0x01
-+#define UOTG_HNP 0x02
-+} UPACKED usb_otg_descriptor_t;
-+
-+/* OTG feature selectors */
-+#define UOTG_B_HNP_ENABLE 3
-+#define UOTG_A_HNP_SUPPORT 4
-+#define UOTG_A_ALT_HNP_SUPPORT 5
-+
-+typedef struct {
-+ uWord wStatus;
-+/* Device status flags */
-+#define UDS_SELF_POWERED 0x0001
-+#define UDS_REMOTE_WAKEUP 0x0002
-+/* Endpoint status flags */
-+#define UES_HALT 0x0001
-+} UPACKED usb_status_t;
-+
-+typedef struct {
-+ uWord wHubStatus;
-+#define UHS_LOCAL_POWER 0x0001
-+#define UHS_OVER_CURRENT 0x0002
-+ uWord wHubChange;
-+} UPACKED usb_hub_status_t;
-+
-+typedef struct {
-+ uWord wPortStatus;
-+#define UPS_CURRENT_CONNECT_STATUS 0x0001
-+#define UPS_PORT_ENABLED 0x0002
-+#define UPS_SUSPEND 0x0004
-+#define UPS_OVERCURRENT_INDICATOR 0x0008
-+#define UPS_RESET 0x0010
-+#define UPS_PORT_POWER 0x0100
-+#define UPS_LOW_SPEED 0x0200
-+#define UPS_HIGH_SPEED 0x0400
-+#define UPS_PORT_TEST 0x0800
-+#define UPS_PORT_INDICATOR 0x1000
-+ uWord wPortChange;
-+#define UPS_C_CONNECT_STATUS 0x0001
-+#define UPS_C_PORT_ENABLED 0x0002
-+#define UPS_C_SUSPEND 0x0004
-+#define UPS_C_OVERCURRENT_INDICATOR 0x0008
-+#define UPS_C_PORT_RESET 0x0010
-+} UPACKED usb_port_status_t;
-+
-+#ifdef _MSC_VER
-+#include <poppack.h>
-+#endif
-+
-+/* Device class codes */
-+#define UDCLASS_IN_INTERFACE 0x00
-+#define UDCLASS_COMM 0x02
-+#define UDCLASS_HUB 0x09
-+#define UDSUBCLASS_HUB 0x00
-+#define UDPROTO_FSHUB 0x00
-+#define UDPROTO_HSHUBSTT 0x01
-+#define UDPROTO_HSHUBMTT 0x02
-+#define UDCLASS_DIAGNOSTIC 0xdc
-+#define UDCLASS_WIRELESS 0xe0
-+#define UDSUBCLASS_RF 0x01
-+#define UDPROTO_BLUETOOTH 0x01
-+#define UDCLASS_VENDOR 0xff
-+
-+/* Interface class codes */
-+#define UICLASS_UNSPEC 0x00
-+
-+#define UICLASS_AUDIO 0x01
-+#define UISUBCLASS_AUDIOCONTROL 1
-+#define UISUBCLASS_AUDIOSTREAM 2
-+#define UISUBCLASS_MIDISTREAM 3
-+
-+#define UICLASS_CDC 0x02 /* communication */
-+#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
-+#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
-+#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
-+#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
-+#define UISUBCLASS_CAPI_CONTROLMODEL 5
-+#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
-+#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
-+#define UIPROTO_CDC_AT 1
-+
-+#define UICLASS_HID 0x03
-+#define UISUBCLASS_BOOT 1
-+#define UIPROTO_BOOT_KEYBOARD 1
-+
-+#define UICLASS_PHYSICAL 0x05
-+
-+#define UICLASS_IMAGE 0x06
-+
-+#define UICLASS_PRINTER 0x07
-+#define UISUBCLASS_PRINTER 1
-+#define UIPROTO_PRINTER_UNI 1
-+#define UIPROTO_PRINTER_BI 2
-+#define UIPROTO_PRINTER_1284 3
-+
-+#define UICLASS_MASS 0x08
-+#define UISUBCLASS_RBC 1
-+#define UISUBCLASS_SFF8020I 2
-+#define UISUBCLASS_QIC157 3
-+#define UISUBCLASS_UFI 4
-+#define UISUBCLASS_SFF8070I 5
-+#define UISUBCLASS_SCSI 6
-+#define UIPROTO_MASS_CBI_I 0
-+#define UIPROTO_MASS_CBI 1
-+#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
-+#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
-+
-+#define UICLASS_HUB 0x09
-+#define UISUBCLASS_HUB 0
-+#define UIPROTO_FSHUB 0
-+#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
-+#define UIPROTO_HSHUBMTT 1
-+
-+#define UICLASS_CDC_DATA 0x0a
-+#define UISUBCLASS_DATA 0
-+#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
-+#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
-+#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
-+#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
-+#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
-+#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
-+#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
-+#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
-+#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
-+#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
-+#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
-+#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
-+#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
-+
-+#define UICLASS_SMARTCARD 0x0b
-+
-+/*#define UICLASS_FIRM_UPD 0x0c*/
-+
-+#define UICLASS_SECURITY 0x0d
-+
-+#define UICLASS_DIAGNOSTIC 0xdc
-+
-+#define UICLASS_WIRELESS 0xe0
-+#define UISUBCLASS_RF 0x01
-+#define UIPROTO_BLUETOOTH 0x01
-+
-+#define UICLASS_APPL_SPEC 0xfe
-+#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
-+#define UISUBCLASS_IRDA 2
-+#define UIPROTO_IRDA 0
-+
-+#define UICLASS_VENDOR 0xff
-+
-+#define USB_HUB_MAX_DEPTH 5
-+
-+/*
-+ * Minimum time a device needs to be powered down to go through
-+ * a power cycle. XXX Are these time in the spec?
-+ */
-+#define USB_POWER_DOWN_TIME 200 /* ms */
-+#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
-+
-+#if 0
-+/* These are the values from the spec. */
-+#define USB_PORT_RESET_DELAY 10 /* ms */
-+#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
-+#define USB_PORT_RESET_RECOVERY 10 /* ms */
-+#define USB_PORT_POWERUP_DELAY 100 /* ms */
-+#define USB_SET_ADDRESS_SETTLE 2 /* ms */
-+#define USB_RESUME_DELAY (20*5) /* ms */
-+#define USB_RESUME_WAIT 10 /* ms */
-+#define USB_RESUME_RECOVERY 10 /* ms */
-+#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
-+#else
-+/* Allow for marginal (i.e. non-conforming) devices. */
-+#define USB_PORT_RESET_DELAY 50 /* ms */
-+#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
-+#define USB_PORT_RESET_RECOVERY 250 /* ms */
-+#define USB_PORT_POWERUP_DELAY 300 /* ms */
-+#define USB_SET_ADDRESS_SETTLE 10 /* ms */
-+#define USB_RESUME_DELAY (50*5) /* ms */
-+#define USB_RESUME_WAIT 50 /* ms */
-+#define USB_RESUME_RECOVERY 50 /* ms */
-+#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
-+#endif
-+
-+#define USB_MIN_POWER 100 /* mA */
-+#define USB_MAX_POWER 500 /* mA */
-+
-+#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
-+
-+#define USB_UNCONFIG_NO 0
-+#define USB_UNCONFIG_INDEX (-1)
-+
-+/*** ioctl() related stuff ***/
-+
-+struct usb_ctl_request {
-+ int ucr_addr;
-+ usb_device_request_t ucr_request;
-+ void *ucr_data;
-+ int ucr_flags;
-+#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
-+ int ucr_actlen; /* actual length transferred */
-+};
-+
-+struct usb_alt_interface {
-+ int uai_config_index;
-+ int uai_interface_index;
-+ int uai_alt_no;
-+};
-+
-+#define USB_CURRENT_CONFIG_INDEX (-1)
-+#define USB_CURRENT_ALT_INDEX (-1)
-+
-+struct usb_config_desc {
-+ int ucd_config_index;
-+ usb_config_descriptor_t ucd_desc;
-+};
-+
-+struct usb_interface_desc {
-+ int uid_config_index;
-+ int uid_interface_index;
-+ int uid_alt_index;
-+ usb_interface_descriptor_t uid_desc;
-+};
-+
-+struct usb_endpoint_desc {
-+ int ued_config_index;
-+ int ued_interface_index;
-+ int ued_alt_index;
-+ int ued_endpoint_index;
-+ usb_endpoint_descriptor_t ued_desc;
-+};
-+
-+struct usb_full_desc {
-+ int ufd_config_index;
-+ u_int ufd_size;
-+ u_char *ufd_data;
-+};
-+
-+struct usb_string_desc {
-+ int usd_string_index;
-+ int usd_language_id;
-+ usb_string_descriptor_t usd_desc;
-+};
-+
-+struct usb_ctl_report_desc {
-+ int ucrd_size;
-+ u_char ucrd_data[1024]; /* filled data size will vary */
-+};
-+
-+typedef struct { u_int32_t cookie; } usb_event_cookie_t;
-+
-+#define USB_MAX_DEVNAMES 4
-+#define USB_MAX_DEVNAMELEN 16
-+struct usb_device_info {
-+ u_int8_t udi_bus;
-+ u_int8_t udi_addr; /* device address */
-+ usb_event_cookie_t udi_cookie;
-+ char udi_product[USB_MAX_STRING_LEN];
-+ char udi_vendor[USB_MAX_STRING_LEN];
-+ char udi_release[8];
-+ u_int16_t udi_productNo;
-+ u_int16_t udi_vendorNo;
-+ u_int16_t udi_releaseNo;
-+ u_int8_t udi_class;
-+ u_int8_t udi_subclass;
-+ u_int8_t udi_protocol;
-+ u_int8_t udi_config;
-+ u_int8_t udi_speed;
-+#define USB_SPEED_UNKNOWN 0
-+#define USB_SPEED_LOW 1
-+#define USB_SPEED_FULL 2
-+#define USB_SPEED_HIGH 3
-+#define USB_SPEED_VARIABLE 4
-+#define USB_SPEED_SUPER 5
-+ int udi_power; /* power consumption in mA, 0 if selfpowered */
-+ int udi_nports;
-+ char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
-+ u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
-+#define USB_PORT_ENABLED 0xff
-+#define USB_PORT_SUSPENDED 0xfe
-+#define USB_PORT_POWERED 0xfd
-+#define USB_PORT_DISABLED 0xfc
-+};
-+
-+struct usb_ctl_report {
-+ int ucr_report;
-+ u_char ucr_data[1024]; /* filled data size will vary */
-+};
-+
-+struct usb_device_stats {
-+ u_long uds_requests[4]; /* indexed by transfer type UE_* */
-+};
-+
-+#define WUSB_MIN_IE 0x80
-+#define WUSB_WCTA_IE 0x80
-+#define WUSB_WCONNECTACK_IE 0x81
-+#define WUSB_WHOSTINFO_IE 0x82
-+#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
-+#define WUHI_CA_RECONN 0x00
-+#define WUHI_CA_LIMITED 0x01
-+#define WUHI_CA_ALL 0x03
-+#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
-+#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
-+#define WUSB_WDEV_DISCONNECT_IE 0x84
-+#define WUSB_WHOST_DISCONNECT_IE 0x85
-+#define WUSB_WRELEASE_CHANNEL_IE 0x86
-+#define WUSB_WWORK_IE 0x87
-+#define WUSB_WCHANNEL_STOP_IE 0x88
-+#define WUSB_WDEV_KEEPALIVE_IE 0x89
-+#define WUSB_WISOCH_DISCARD_IE 0x8A
-+#define WUSB_WRESETDEVICE_IE 0x8B
-+#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
-+#define WUSB_MAX_IE 0x8C
-+
-+/* Device Notification Types */
-+
-+#define WUSB_DN_MIN 0x01
-+#define WUSB_DN_CONNECT 0x01
-+# define WUSB_DA_OLDCONN 0x00
-+# define WUSB_DA_NEWCONN 0x01
-+# define WUSB_DA_SELF_BEACON 0x02
-+# define WUSB_DA_DIR_BEACON 0x04
-+# define WUSB_DA_NO_BEACON 0x06
-+#define WUSB_DN_DISCONNECT 0x02
-+#define WUSB_DN_EPRDY 0x03
-+#define WUSB_DN_MASAVAILCHANGED 0x04
-+#define WUSB_DN_REMOTEWAKEUP 0x05
-+#define WUSB_DN_SLEEP 0x06
-+#define WUSB_DN_ALIVE 0x07
-+#define WUSB_DN_MAX 0x07
-+
-+#ifdef _MSC_VER
-+#include <pshpack1.h>
-+#endif
-+
-+/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
-+typedef struct wusb_hndshk_data {
-+ uByte bMessageNumber;
-+ uByte bStatus;
-+ uByte tTKID[3];
-+ uByte bReserved;
-+ uByte CDID[16];
-+ uByte Nonce[16];
-+ uByte MIC[8];
-+} UPACKED wusb_hndshk_data_t;
-+#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
-+
-+/* WUSB Connection Context */
-+typedef struct wusb_conn_context {
-+ uByte CHID [16];
-+ uByte CDID [16];
-+ uByte CK [16];
-+} UPACKED wusb_conn_context_t;
-+
-+/* WUSB Security Descriptor */
-+typedef struct wusb_security_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uWord wTotalLength;
-+ uByte bNumEncryptionTypes;
-+} UPACKED wusb_security_desc_t;
-+
-+/* WUSB Encryption Type Descriptor */
-+typedef struct wusb_encrypt_type_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+
-+ uByte bEncryptionType;
-+#define WUETD_UNSECURE 0
-+#define WUETD_WIRED 1
-+#define WUETD_CCM_1 2
-+#define WUETD_RSA_1 3
-+
-+ uByte bEncryptionValue;
-+ uByte bAuthKeyIndex;
-+} UPACKED wusb_encrypt_type_desc_t;
-+
-+/* WUSB Key Descriptor */
-+typedef struct wusb_key_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte tTKID[3];
-+ uByte bReserved;
-+ uByte KeyData[1]; /* variable length */
-+} UPACKED wusb_key_desc_t;
-+
-+/* WUSB BOS Descriptor (Binary device Object Store) */
-+typedef struct wusb_bos_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uWord wTotalLength;
-+ uByte bNumDeviceCaps;
-+} UPACKED wusb_bos_desc_t;
-+
-+#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
-+typedef struct usb_dev_cap_20_ext_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bDevCapabilityType;
-+#define USB_20_EXT_LPM 0x02
-+ uDWord bmAttributes;
-+} UPACKED usb_dev_cap_20_ext_desc_t;
-+
-+#define USB_DEVICE_CAPABILITY_SS_USB 0x03
-+typedef struct usb_dev_cap_ss_usb {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bDevCapabilityType;
-+#define USB_DC_SS_USB_LTM_CAPABLE 0x02
-+ uByte bmAttributes;
-+#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
-+#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
-+#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
-+#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
-+ uWord wSpeedsSupported;
-+ uByte bFunctionalitySupport;
-+ uByte bU1DevExitLat;
-+ uWord wU2DevExitLat;
-+} UPACKED usb_dev_cap_ss_usb_t;
-+
-+#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
-+typedef struct usb_dev_cap_container_id {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bDevCapabilityType;
-+ uByte bReserved;
-+ uByte containerID[16];
-+} UPACKED usb_dev_cap_container_id_t;
-+
-+/* Device Capability Type Codes */
-+#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
-+
-+/* Device Capability Descriptor */
-+typedef struct wusb_dev_cap_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bDevCapabilityType;
-+ uByte caps[1]; /* Variable length */
-+} UPACKED wusb_dev_cap_desc_t;
-+
-+/* Device Capability Descriptor */
-+typedef struct wusb_dev_cap_uwb_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bDevCapabilityType;
-+ uByte bmAttributes;
-+ uWord wPHYRates; /* Bitmap */
-+ uByte bmTFITXPowerInfo;
-+ uByte bmFFITXPowerInfo;
-+ uWord bmBandGroup;
-+ uByte bReserved;
-+} UPACKED wusb_dev_cap_uwb_desc_t;
-+
-+/* Wireless USB Endpoint Companion Descriptor */
-+typedef struct wusb_endpoint_companion_desc {
-+ uByte bLength;
-+ uByte bDescriptorType;
-+ uByte bMaxBurst;
-+ uByte bMaxSequence;
-+ uWord wMaxStreamDelay;
-+ uWord wOverTheAirPacketSize;
-+ uByte bOverTheAirInterval;
-+ uByte bmCompAttributes;
-+} UPACKED wusb_endpoint_companion_desc_t;
-+
-+/* Wireless USB Numeric Association M1 Data Structure */
-+typedef struct wusb_m1_data {
-+ uByte version;
-+ uWord langId;
-+ uByte deviceFriendlyNameLength;
-+ uByte sha_256_m3[32];
-+ uByte deviceFriendlyName[256];
-+} UPACKED wusb_m1_data_t;
-+
-+typedef struct wusb_m2_data {
-+ uByte version;
-+ uWord langId;
-+ uByte hostFriendlyNameLength;
-+ uByte pkh[384];
-+ uByte hostFriendlyName[256];
-+} UPACKED wusb_m2_data_t;
-+
-+typedef struct wusb_m3_data {
-+ uByte pkd[384];
-+ uByte nd;
-+} UPACKED wusb_m3_data_t;
-+
-+typedef struct wusb_m4_data {
-+ uDWord _attributeTypeIdAndLength_1;
-+ uWord associationTypeId;
-+
-+ uDWord _attributeTypeIdAndLength_2;
-+ uWord associationSubTypeId;
-+
-+ uDWord _attributeTypeIdAndLength_3;
-+ uDWord length;
-+
-+ uDWord _attributeTypeIdAndLength_4;
-+ uDWord associationStatus;
-+
-+ uDWord _attributeTypeIdAndLength_5;
-+ uByte chid[16];
-+
-+ uDWord _attributeTypeIdAndLength_6;
-+ uByte cdid[16];
-+
-+ uDWord _attributeTypeIdAndLength_7;
-+ uByte bandGroups[2];
-+} UPACKED wusb_m4_data_t;
-+
-+#ifdef _MSC_VER
-+#include <poppack.h>
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _USB_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/doc/doxygen.cfg linux-3.11.10/drivers/usb/host/dwc_otg/doc/doxygen.cfg
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/doc/doxygen.cfg 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/doc/doxygen.cfg 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,224 @@
-+# Doxyfile 1.3.9.1
-+
-+#---------------------------------------------------------------------------
-+# Project related configuration options
-+#---------------------------------------------------------------------------
-+PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
-+PROJECT_NUMBER = v3.00a
-+OUTPUT_DIRECTORY = ./doc/
-+CREATE_SUBDIRS = NO
-+OUTPUT_LANGUAGE = English
-+BRIEF_MEMBER_DESC = YES
-+REPEAT_BRIEF = YES
-+ABBREVIATE_BRIEF = "The $name class" \
-+ "The $name widget" \
-+ "The $name file" \
-+ is \
-+ provides \
-+ specifies \
-+ contains \
-+ represents \
-+ a \
-+ an \
-+ the
-+ALWAYS_DETAILED_SEC = NO
-+INLINE_INHERITED_MEMB = NO
-+FULL_PATH_NAMES = NO
-+STRIP_FROM_PATH =
-+STRIP_FROM_INC_PATH =
-+SHORT_NAMES = NO
-+JAVADOC_AUTOBRIEF = YES
-+MULTILINE_CPP_IS_BRIEF = NO
-+INHERIT_DOCS = YES
-+DISTRIBUTE_GROUP_DOC = NO
-+TAB_SIZE = 8
-+ALIASES =
-+OPTIMIZE_OUTPUT_FOR_C = YES
-+OPTIMIZE_OUTPUT_JAVA = NO
-+SUBGROUPING = YES
-+#---------------------------------------------------------------------------
-+# Build related configuration options
-+#---------------------------------------------------------------------------
-+EXTRACT_ALL = NO
-+EXTRACT_PRIVATE = YES
-+EXTRACT_STATIC = YES
-+EXTRACT_LOCAL_CLASSES = YES
-+EXTRACT_LOCAL_METHODS = NO
-+HIDE_UNDOC_MEMBERS = NO
-+HIDE_UNDOC_CLASSES = NO
-+HIDE_FRIEND_COMPOUNDS = NO
-+HIDE_IN_BODY_DOCS = NO
-+INTERNAL_DOCS = NO
-+CASE_SENSE_NAMES = NO
-+HIDE_SCOPE_NAMES = NO
-+SHOW_INCLUDE_FILES = YES
-+INLINE_INFO = YES
-+SORT_MEMBER_DOCS = NO
-+SORT_BRIEF_DOCS = NO
-+SORT_BY_SCOPE_NAME = NO
-+GENERATE_TODOLIST = YES
-+GENERATE_TESTLIST = YES
-+GENERATE_BUGLIST = YES
-+GENERATE_DEPRECATEDLIST= YES
-+ENABLED_SECTIONS =
-+MAX_INITIALIZER_LINES = 30
-+SHOW_USED_FILES = YES
-+SHOW_DIRECTORIES = YES
-+#---------------------------------------------------------------------------
-+# configuration options related to warning and progress messages
-+#---------------------------------------------------------------------------
-+QUIET = YES
-+WARNINGS = YES
-+WARN_IF_UNDOCUMENTED = NO
-+WARN_IF_DOC_ERROR = YES
-+WARN_FORMAT = "$file:$line: $text"
-+WARN_LOGFILE =
-+#---------------------------------------------------------------------------
-+# configuration options related to the input files
-+#---------------------------------------------------------------------------
-+INPUT = .
-+FILE_PATTERNS = *.c \
-+ *.h \
-+ ./linux/*.c \
-+ ./linux/*.h
-+RECURSIVE = NO
-+EXCLUDE = ./test/ \
-+ ./dwc_otg/.AppleDouble/
-+EXCLUDE_SYMLINKS = YES
-+EXCLUDE_PATTERNS = *.mod.*
-+EXAMPLE_PATH =
-+EXAMPLE_PATTERNS = *
-+EXAMPLE_RECURSIVE = NO
-+IMAGE_PATH =
-+INPUT_FILTER =
-+FILTER_PATTERNS =
-+FILTER_SOURCE_FILES = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to source browsing
-+#---------------------------------------------------------------------------
-+SOURCE_BROWSER = YES
-+INLINE_SOURCES = NO
-+STRIP_CODE_COMMENTS = YES
-+REFERENCED_BY_RELATION = NO
-+REFERENCES_RELATION = NO
-+VERBATIM_HEADERS = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the alphabetical class index
-+#---------------------------------------------------------------------------
-+ALPHABETICAL_INDEX = NO
-+COLS_IN_ALPHA_INDEX = 5
-+IGNORE_PREFIX =
-+#---------------------------------------------------------------------------
-+# configuration options related to the HTML output
-+#---------------------------------------------------------------------------
-+GENERATE_HTML = YES
-+HTML_OUTPUT = html
-+HTML_FILE_EXTENSION = .html
-+HTML_HEADER =
-+HTML_FOOTER =
-+HTML_STYLESHEET =
-+HTML_ALIGN_MEMBERS = YES
-+GENERATE_HTMLHELP = NO
-+CHM_FILE =
-+HHC_LOCATION =
-+GENERATE_CHI = NO
-+BINARY_TOC = NO
-+TOC_EXPAND = NO
-+DISABLE_INDEX = NO
-+ENUM_VALUES_PER_LINE = 4
-+GENERATE_TREEVIEW = YES
-+TREEVIEW_WIDTH = 250
-+#---------------------------------------------------------------------------
-+# configuration options related to the LaTeX output
-+#---------------------------------------------------------------------------
-+GENERATE_LATEX = NO
-+LATEX_OUTPUT = latex
-+LATEX_CMD_NAME = latex
-+MAKEINDEX_CMD_NAME = makeindex
-+COMPACT_LATEX = NO
-+PAPER_TYPE = a4wide
-+EXTRA_PACKAGES =
-+LATEX_HEADER =
-+PDF_HYPERLINKS = NO
-+USE_PDFLATEX = NO
-+LATEX_BATCHMODE = NO
-+LATEX_HIDE_INDICES = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the RTF output
-+#---------------------------------------------------------------------------
-+GENERATE_RTF = NO
-+RTF_OUTPUT = rtf
-+COMPACT_RTF = NO
-+RTF_HYPERLINKS = NO
-+RTF_STYLESHEET_FILE =
-+RTF_EXTENSIONS_FILE =
-+#---------------------------------------------------------------------------
-+# configuration options related to the man page output
-+#---------------------------------------------------------------------------
-+GENERATE_MAN = NO
-+MAN_OUTPUT = man
-+MAN_EXTENSION = .3
-+MAN_LINKS = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the XML output
-+#---------------------------------------------------------------------------
-+GENERATE_XML = NO
-+XML_OUTPUT = xml
-+XML_SCHEMA =
-+XML_DTD =
-+XML_PROGRAMLISTING = YES
-+#---------------------------------------------------------------------------
-+# configuration options for the AutoGen Definitions output
-+#---------------------------------------------------------------------------
-+GENERATE_AUTOGEN_DEF = NO
-+#---------------------------------------------------------------------------
-+# configuration options related to the Perl module output
-+#---------------------------------------------------------------------------
-+GENERATE_PERLMOD = NO
-+PERLMOD_LATEX = NO
-+PERLMOD_PRETTY = YES
-+PERLMOD_MAKEVAR_PREFIX =
-+#---------------------------------------------------------------------------
-+# Configuration options related to the preprocessor
-+#---------------------------------------------------------------------------
-+ENABLE_PREPROCESSING = YES
-+MACRO_EXPANSION = YES
-+EXPAND_ONLY_PREDEF = YES
-+SEARCH_INCLUDES = YES
-+INCLUDE_PATH =
-+INCLUDE_FILE_PATTERNS =
-+PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
-+EXPAND_AS_DEFINED = DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW DWC_OTG_DEVICE_ATTR_BITFIELD_STORE DWC_OTG_DEVICE_ATTR_BITFIELD_RW DWC_OTG_DEVICE_ATTR_BITFIELD_RO DWC_OTG_DEVICE_ATTR_REG_SHOW DWC_OTG_DEVICE_ATTR_REG_STORE DWC_OTG_DEVICE_ATTR_REG32_RW DWC_OTG_DEVICE_ATTR_REG32_RO DWC_EN_ISOC
-+SKIP_FUNCTION_MACROS = NO
-+#---------------------------------------------------------------------------
-+# Configuration::additions related to external references
-+#---------------------------------------------------------------------------
-+TAGFILES =
-+GENERATE_TAGFILE =
-+ALLEXTERNALS = NO
-+EXTERNAL_GROUPS = YES
-+PERL_PATH = /usr/bin/perl
-+#---------------------------------------------------------------------------
-+# Configuration options related to the dot tool
-+#---------------------------------------------------------------------------
-+CLASS_DIAGRAMS = YES
-+HIDE_UNDOC_RELATIONS = YES
-+HAVE_DOT = NO
-+CLASS_GRAPH = YES
-+COLLABORATION_GRAPH = YES
-+UML_LOOK = NO
-+TEMPLATE_RELATIONS = NO
-+INCLUDE_GRAPH = YES
-+INCLUDED_BY_GRAPH = YES
-+CALL_GRAPH = NO
-+GRAPHICAL_HIERARCHY = YES
-+DOT_IMAGE_FORMAT = png
-+DOT_PATH =
-+DOTFILE_DIRS =
-+MAX_DOT_GRAPH_DEPTH = 1000
-+GENERATE_LEGEND = YES
-+DOT_CLEANUP = YES
-+#---------------------------------------------------------------------------
-+# Configuration::additions related to the search engine
-+#---------------------------------------------------------------------------
-+SEARCHENGINE = NO
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dummy_audio.c linux-3.11.10/drivers/usb/host/dwc_otg/dummy_audio.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dummy_audio.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dummy_audio.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1575 @@
-+/*
-+ * zero.c -- Gadget Zero, for USB development
-+ *
-+ * Copyright (C) 2003-2004 David Brownell
-+ * 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,
-+ * without modification.
-+ * 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. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") as published by the Free Software
-+ * Foundation, either version 2 of that License or (at your option) any
-+ * later version.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+
-+/*
-+ * Gadget Zero only needs two bulk endpoints, and is an example of how you
-+ * can write a hardware-agnostic gadget driver running inside a USB device.
-+ *
-+ * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
-+ * affect most of the driver.
-+ *
-+ * Use it with the Linux host/master side "usbtest" driver to get a basic
-+ * functional test of your device-side usb stack, or with "usb-skeleton".
-+ *
-+ * It supports two similar configurations. One sinks whatever the usb host
-+ * writes, and in return sources zeroes. The other loops whatever the host
-+ * writes back, so the host can read it. Module options include:
-+ *
-+ * buflen=N default N=4096, buffer size used
-+ * qlen=N default N=32, how many buffers in the loopback queue
-+ * loopdefault default false, list loopback config first
-+ *
-+ * Many drivers will only have one configuration, letting them be much
-+ * simpler if they also don't support high speed operation (like this
-+ * driver does).
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/ioport.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/smp_lock.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/timer.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/uts.h>
-+#include <linux/version.h>
-+#include <linux/device.h>
-+#include <linux/moduleparam.h>
-+#include <linux/proc_fs.h>
-+
-+#include <asm/byteorder.h>
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/system.h>
-+#include <asm/unaligned.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
-+# include <linux/usb/ch9.h>
-+#else
-+# include <linux/usb_ch9.h>
-+#endif
-+
-+#include <linux/usb_gadget.h>
-+
-+
-+/*-------------------------------------------------------------------------*/
-+/*-------------------------------------------------------------------------*/
-+
-+
-+static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
-+{
-+ int count = 0;
-+ u8 c;
-+ u16 uchar;
-+
-+ /* this insists on correct encodings, though not minimal ones.
-+ * BUT it currently rejects legit 4-byte UTF-8 code points,
-+ * which need surrogate pairs. (Unicode 3.1 can use them.)
-+ */
-+ while (len != 0 && (c = (u8) *s++) != 0) {
-+ if (unlikely(c & 0x80)) {
-+ // 2-byte sequence:
-+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-+ if ((c & 0xe0) == 0xc0) {
-+ uchar = (c & 0x1f) << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ // 3-byte sequence (most CJKV characters):
-+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-+ } else if ((c & 0xf0) == 0xe0) {
-+ uchar = (c & 0x0f) << 12;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c << 6;
-+
-+ c = (u8) *s++;
-+ if ((c & 0xc0) != 0xc0)
-+ goto fail;
-+ c &= 0x3f;
-+ uchar |= c;
-+
-+ /* no bogus surrogates */
-+ if (0xd800 <= uchar && uchar <= 0xdfff)
-+ goto fail;
-+
-+ // 4-byte sequence (surrogate pairs, currently rare):
-+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-+ // (uuuuu = wwww + 1)
-+ // FIXME accept the surrogate code points (only)
-+
-+ } else
-+ goto fail;
-+ } else
-+ uchar = c;
-+ put_unaligned (cpu_to_le16 (uchar), cp++);
-+ count++;
-+ len--;
-+ }
-+ return count;
-+fail:
-+ return -1;
-+}
-+
-+
-+/**
-+ * usb_gadget_get_string - fill out a string descriptor
-+ * @table: of c strings encoded using UTF-8
-+ * @id: string id, from low byte of wValue in get string descriptor
-+ * @buf: at least 256 bytes
-+ *
-+ * Finds the UTF-8 string matching the ID, and converts it into a
-+ * string descriptor in utf16-le.
-+ * Returns length of descriptor (always even) or negative errno
-+ *
-+ * If your driver needs stings in multiple languages, you'll probably
-+ * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
-+ * using this routine after choosing which set of UTF-8 strings to use.
-+ * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
-+ * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
-+ * characters (which are also widely used in C strings).
-+ */
-+int
-+usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
-+{
-+ struct usb_string *s;
-+ int len;
-+
-+ /* descriptor 0 has the language id */
-+ if (id == 0) {
-+ buf [0] = 4;
-+ buf [1] = USB_DT_STRING;
-+ buf [2] = (u8) table->language;
-+ buf [3] = (u8) (table->language >> 8);
-+ return 4;
-+ }
-+ for (s = table->strings; s && s->s; s++)
-+ if (s->id == id)
-+ break;
-+
-+ /* unrecognized: stall. */
-+ if (!s || !s->s)
-+ return -EINVAL;
-+
-+ /* string descriptors have length, tag, then UTF16-LE text */
-+ len = min ((size_t) 126, strlen (s->s));
-+ memset (buf + 2, 0, 2 * len); /* zero all the bytes */
-+ len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
-+ if (len < 0)
-+ return -EINVAL;
-+ buf [0] = (len + 1) * 2;
-+ buf [1] = USB_DT_STRING;
-+ return buf [0];
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+/*-------------------------------------------------------------------------*/
-+
-+
-+/**
-+ * usb_descriptor_fillbuf - fill buffer with descriptors
-+ * @buf: Buffer to be filled
-+ * @buflen: Size of buf
-+ * @src: Array of descriptor pointers, terminated by null pointer.
-+ *
-+ * Copies descriptors into the buffer, returning the length or a
-+ * negative error code if they can't all be copied. Useful when
-+ * assembling descriptors for an associated set of interfaces used
-+ * as part of configuring a composite device; or in other cases where
-+ * sets of descriptors need to be marshaled.
-+ */
-+int
-+usb_descriptor_fillbuf(void *buf, unsigned buflen,
-+ const struct usb_descriptor_header **src)
-+{
-+ u8 *dest = buf;
-+
-+ if (!src)
-+ return -EINVAL;
-+
-+ /* fill buffer from src[] until null descriptor ptr */
-+ for (; 0 != *src; src++) {
-+ unsigned len = (*src)->bLength;
-+
-+ if (len > buflen)
-+ return -EINVAL;
-+ memcpy(dest, *src, len);
-+ buflen -= len;
-+ dest += len;
-+ }
-+ return dest - (u8 *)buf;
-+}
-+
-+
-+/**
-+ * usb_gadget_config_buf - builts a complete configuration descriptor
-+ * @config: Header for the descriptor, including characteristics such
-+ * as power requirements and number of interfaces.
-+ * @desc: Null-terminated vector of pointers to the descriptors (interface,
-+ * endpoint, etc) defining all functions in this device configuration.
-+ * @buf: Buffer for the resulting configuration descriptor.
-+ * @length: Length of buffer. If this is not big enough to hold the
-+ * entire configuration descriptor, an error code will be returned.
-+ *
-+ * This copies descriptors into the response buffer, building a descriptor
-+ * for that configuration. It returns the buffer length or a negative
-+ * status code. The config.wTotalLength field is set to match the length
-+ * of the result, but other descriptor fields (including power usage and
-+ * interface count) must be set by the caller.
-+ *
-+ * Gadget drivers could use this when constructing a config descriptor
-+ * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
-+ * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
-+ */
-+int usb_gadget_config_buf(
-+ const struct usb_config_descriptor *config,
-+ void *buf,
-+ unsigned length,
-+ const struct usb_descriptor_header **desc
-+)
-+{
-+ struct usb_config_descriptor *cp = buf;
-+ int len;
-+
-+ /* config descriptor first */
-+ if (length < USB_DT_CONFIG_SIZE || !desc)
-+ return -EINVAL;
-+ *cp = *config;
-+
-+ /* then interface/endpoint/class/vendor/... */
-+ len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
-+ length - USB_DT_CONFIG_SIZE, desc);
-+ if (len < 0)
-+ return len;
-+ len += USB_DT_CONFIG_SIZE;
-+ if (len > 0xffff)
-+ return -EINVAL;
-+
-+ /* patch up the config descriptor */
-+ cp->bLength = USB_DT_CONFIG_SIZE;
-+ cp->bDescriptorType = USB_DT_CONFIG;
-+ cp->wTotalLength = cpu_to_le16(len);
-+ cp->bmAttributes |= USB_CONFIG_ATT_ONE;
-+ return len;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+/*-------------------------------------------------------------------------*/
-+
-+
-+#define RBUF_LEN (1024*1024)
-+static int rbuf_start;
-+static int rbuf_len;
-+static __u8 rbuf[RBUF_LEN];
-+
-+/*-------------------------------------------------------------------------*/
-+
-+#define DRIVER_VERSION "St Patrick's Day 2004"
-+
-+static const char shortname [] = "zero";
-+static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
-+
-+static const char source_sink [] = "source and sink data";
-+static const char loopback [] = "loop input to output";
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * driver assumes self-powered hardware, and
-+ * has no way for users to trigger remote wakeup.
-+ *
-+ * this version autoconfigures as much as possible,
-+ * which is reasonable for most "bulk-only" drivers.
-+ */
-+static const char *EP_IN_NAME; /* source */
-+static const char *EP_OUT_NAME; /* sink */
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* big enough to hold our biggest descriptor */
-+#define USB_BUFSIZ 512
-+
-+struct zero_dev {
-+ spinlock_t lock;
-+ struct usb_gadget *gadget;
-+ struct usb_request *req; /* for control responses */
-+
-+ /* when configured, we have one of two configs:
-+ * - source data (in to host) and sink it (out from host)
-+ * - or loop it back (out from host back in to host)
-+ */
-+ u8 config;
-+ struct usb_ep *in_ep, *out_ep;
-+
-+ /* autoresume timer */
-+ struct timer_list resume;
-+};
-+
-+#define xprintk(d,level,fmt,args...) \
-+ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-+
-+#ifdef DEBUG
-+#define DBG(dev,fmt,args...) \
-+ xprintk(dev , KERN_DEBUG , fmt , ## args)
-+#else
-+#define DBG(dev,fmt,args...) \
-+ do { } while (0)
-+#endif /* DEBUG */
-+
-+#ifdef VERBOSE
-+#define VDBG DBG
-+#else
-+#define VDBG(dev,fmt,args...) \
-+ do { } while (0)
-+#endif /* VERBOSE */
-+
-+#define ERROR(dev,fmt,args...) \
-+ xprintk(dev , KERN_ERR , fmt , ## args)
-+#define WARN(dev,fmt,args...) \
-+ xprintk(dev , KERN_WARNING , fmt , ## args)
-+#define INFO(dev,fmt,args...) \
-+ xprintk(dev , KERN_INFO , fmt , ## args)
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static unsigned buflen = 4096;
-+static unsigned qlen = 32;
-+static unsigned pattern = 0;
-+
-+module_param (buflen, uint, S_IRUGO|S_IWUSR);
-+module_param (qlen, uint, S_IRUGO|S_IWUSR);
-+module_param (pattern, uint, S_IRUGO|S_IWUSR);
-+
-+/*
-+ * if it's nonzero, autoresume says how many seconds to wait
-+ * before trying to wake up the host after suspend.
-+ */
-+static unsigned autoresume = 0;
-+module_param (autoresume, uint, 0);
-+
-+/*
-+ * Normally the "loopback" configuration is second (index 1) so
-+ * it's not the default. Here's where to change that order, to
-+ * work better with hosts where config changes are problematic.
-+ * Or controllers (like superh) that only support one config.
-+ */
-+static int loopdefault = 0;
-+
-+module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Thanks to NetChip Technologies for donating this product ID.
-+ *
-+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
-+ * Instead: allocate your own, using normal USB-IF procedures.
-+ */
-+#ifndef CONFIG_USB_ZERO_HNPTEST
-+#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
-+#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
-+#else
-+#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
-+#define DRIVER_PRODUCT_NUM 0xbadd
-+#endif
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * DESCRIPTORS ... most are static, but strings and (full)
-+ * configuration descriptors are built on demand.
-+ */
-+
-+/*
-+#define STRING_MANUFACTURER 25
-+#define STRING_PRODUCT 42
-+#define STRING_SERIAL 101
-+*/
-+#define STRING_MANUFACTURER 1
-+#define STRING_PRODUCT 2
-+#define STRING_SERIAL 3
-+
-+#define STRING_SOURCE_SINK 250
-+#define STRING_LOOPBACK 251
-+
-+/*
-+ * This device advertises two configurations; these numbers work
-+ * on a pxa250 as well as more flexible hardware.
-+ */
-+#define CONFIG_SOURCE_SINK 3
-+#define CONFIG_LOOPBACK 2
-+
-+/*
-+static struct usb_device_descriptor
-+device_desc = {
-+ .bLength = sizeof device_desc,
-+ .bDescriptorType = USB_DT_DEVICE,
-+
-+ .bcdUSB = __constant_cpu_to_le16 (0x0200),
-+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
-+
-+ .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
-+ .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
-+ .iManufacturer = STRING_MANUFACTURER,
-+ .iProduct = STRING_PRODUCT,
-+ .iSerialNumber = STRING_SERIAL,
-+ .bNumConfigurations = 2,
-+};
-+*/
-+static struct usb_device_descriptor
-+device_desc = {
-+ .bLength = sizeof device_desc,
-+ .bDescriptorType = USB_DT_DEVICE,
-+ .bcdUSB = __constant_cpu_to_le16 (0x0100),
-+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
-+ .bDeviceSubClass = 0,
-+ .bDeviceProtocol = 0,
-+ .bMaxPacketSize0 = 64,
-+ .bcdDevice = __constant_cpu_to_le16 (0x0100),
-+ .idVendor = __constant_cpu_to_le16 (0x0499),
-+ .idProduct = __constant_cpu_to_le16 (0x3002),
-+ .iManufacturer = STRING_MANUFACTURER,
-+ .iProduct = STRING_PRODUCT,
-+ .iSerialNumber = STRING_SERIAL,
-+ .bNumConfigurations = 1,
-+};
-+
-+static struct usb_config_descriptor
-+z_config = {
-+ .bLength = sizeof z_config,
-+ .bDescriptorType = USB_DT_CONFIG,
-+
-+ /* compute wTotalLength on the fly */
-+ .bNumInterfaces = 2,
-+ .bConfigurationValue = 1,
-+ .iConfiguration = 0,
-+ .bmAttributes = 0x40,
-+ .bMaxPower = 0, /* self-powered */
-+};
-+
-+
-+static struct usb_otg_descriptor
-+otg_descriptor = {
-+ .bLength = sizeof otg_descriptor,
-+ .bDescriptorType = USB_DT_OTG,
-+
-+ .bmAttributes = USB_OTG_SRP,
-+};
-+
-+/* one interface in each configuration */
-+#ifdef CONFIG_USB_GADGET_DUALSPEED
-+
-+/*
-+ * usb 2.0 devices need to expose both high speed and full speed
-+ * descriptors, unless they only run at full speed.
-+ *
-+ * that means alternate endpoint descriptors (bigger packets)
-+ * and a "device qualifier" ... plus more construction options
-+ * for the config descriptor.
-+ */
-+
-+static struct usb_qualifier_descriptor
-+dev_qualifier = {
-+ .bLength = sizeof dev_qualifier,
-+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
-+
-+ .bcdUSB = __constant_cpu_to_le16 (0x0200),
-+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
-+
-+ .bNumConfigurations = 2,
-+};
-+
-+
-+struct usb_cs_as_general_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+
-+ __u8 bDescriptorSubType;
-+ __u8 bTerminalLink;
-+ __u8 bDelay;
-+ __u16 wFormatTag;
-+} __attribute__ ((packed));
-+
-+struct usb_cs_as_format_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+
-+ __u8 bDescriptorSubType;
-+ __u8 bFormatType;
-+ __u8 bNrChannels;
-+ __u8 bSubframeSize;
-+ __u8 bBitResolution;
-+ __u8 bSamfreqType;
-+ __u8 tLowerSamFreq[3];
-+ __u8 tUpperSamFreq[3];
-+} __attribute__ ((packed));
-+
-+static const struct usb_interface_descriptor
-+z_audio_control_if_desc = {
-+ .bLength = sizeof z_audio_control_if_desc,
-+ .bDescriptorType = USB_DT_INTERFACE,
-+ .bInterfaceNumber = 0,
-+ .bAlternateSetting = 0,
-+ .bNumEndpoints = 0,
-+ .bInterfaceClass = USB_CLASS_AUDIO,
-+ .bInterfaceSubClass = 0x1,
-+ .bInterfaceProtocol = 0,
-+ .iInterface = 0,
-+};
-+
-+static const struct usb_interface_descriptor
-+z_audio_if_desc = {
-+ .bLength = sizeof z_audio_if_desc,
-+ .bDescriptorType = USB_DT_INTERFACE,
-+ .bInterfaceNumber = 1,
-+ .bAlternateSetting = 0,
-+ .bNumEndpoints = 0,
-+ .bInterfaceClass = USB_CLASS_AUDIO,
-+ .bInterfaceSubClass = 0x2,
-+ .bInterfaceProtocol = 0,
-+ .iInterface = 0,
-+};
-+
-+static const struct usb_interface_descriptor
-+z_audio_if_desc2 = {
-+ .bLength = sizeof z_audio_if_desc,
-+ .bDescriptorType = USB_DT_INTERFACE,
-+ .bInterfaceNumber = 1,
-+ .bAlternateSetting = 1,
-+ .bNumEndpoints = 1,
-+ .bInterfaceClass = USB_CLASS_AUDIO,
-+ .bInterfaceSubClass = 0x2,
-+ .bInterfaceProtocol = 0,
-+ .iInterface = 0,
-+};
-+
-+static const struct usb_cs_as_general_descriptor
-+z_audio_cs_as_if_desc = {
-+ .bLength = 7,
-+ .bDescriptorType = 0x24,
-+
-+ .bDescriptorSubType = 0x01,
-+ .bTerminalLink = 0x01,
-+ .bDelay = 0x0,
-+ .wFormatTag = __constant_cpu_to_le16 (0x0001)
-+};
-+
-+
-+static const struct usb_cs_as_format_descriptor
-+z_audio_cs_as_format_desc = {
-+ .bLength = 0xe,
-+ .bDescriptorType = 0x24,
-+
-+ .bDescriptorSubType = 2,
-+ .bFormatType = 1,
-+ .bNrChannels = 1,
-+ .bSubframeSize = 1,
-+ .bBitResolution = 8,
-+ .bSamfreqType = 0,
-+ .tLowerSamFreq = {0x7e, 0x13, 0x00},
-+ .tUpperSamFreq = {0xe2, 0xd6, 0x00},
-+};
-+
-+static const struct usb_endpoint_descriptor
-+z_iso_ep = {
-+ .bLength = 0x09,
-+ .bDescriptorType = 0x05,
-+ .bEndpointAddress = 0x04,
-+ .bmAttributes = 0x09,
-+ .wMaxPacketSize = 0x0038,
-+ .bInterval = 0x01,
-+ .bRefresh = 0x00,
-+ .bSynchAddress = 0x00,
-+};
-+
-+static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
-+
-+// 9 bytes
-+static char z_ac_interface_header_desc[] =
-+{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
-+
-+// 12 bytes
-+static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
-+ 0x03, 0x00, 0x00, 0x00};
-+// 13 bytes
-+static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
-+ 0x02, 0x00, 0x02, 0x00, 0x00};
-+// 9 bytes
-+static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
-+ 0x00};
-+
-+static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
-+ 0x00};
-+
-+static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
-+
-+static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
-+ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
-+
-+static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
-+ 0x00};
-+
-+static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
-+
-+static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
-+ 0x00};
-+
-+static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
-+
-+static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
-+ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
-+
-+static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
-+ 0x00};
-+
-+static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
-+
-+static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
-+ 0x00};
-+
-+static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
-+
-+static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
-+ 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
-+
-+static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
-+ 0x00};
-+
-+static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
-+
-+static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
-+ 0x00};
-+
-+static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
-+
-+static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
-+ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
-+
-+static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
-+ 0x00};
-+
-+static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
-+
-+static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
-+ 0x00};
-+
-+static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
-+
-+static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
-+ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
-+
-+static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
-+ 0x00};
-+
-+static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
-+
-+
-+
-+static const struct usb_descriptor_header *z_function [] = {
-+ (struct usb_descriptor_header *) &z_audio_control_if_desc,
-+ (struct usb_descriptor_header *) &z_ac_interface_header_desc,
-+ (struct usb_descriptor_header *) &z_0,
-+ (struct usb_descriptor_header *) &z_1,
-+ (struct usb_descriptor_header *) &z_2,
-+ (struct usb_descriptor_header *) &z_audio_if_desc,
-+ (struct usb_descriptor_header *) &z_audio_if_desc2,
-+ (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
-+ (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
-+ (struct usb_descriptor_header *) &z_iso_ep,
-+ (struct usb_descriptor_header *) &z_iso_ep2,
-+ (struct usb_descriptor_header *) &za_0,
-+ (struct usb_descriptor_header *) &za_1,
-+ (struct usb_descriptor_header *) &za_2,
-+ (struct usb_descriptor_header *) &za_3,
-+ (struct usb_descriptor_header *) &za_4,
-+ (struct usb_descriptor_header *) &za_5,
-+ (struct usb_descriptor_header *) &za_6,
-+ (struct usb_descriptor_header *) &za_7,
-+ (struct usb_descriptor_header *) &za_8,
-+ (struct usb_descriptor_header *) &za_9,
-+ (struct usb_descriptor_header *) &za_10,
-+ (struct usb_descriptor_header *) &za_11,
-+ (struct usb_descriptor_header *) &za_12,
-+ (struct usb_descriptor_header *) &za_13,
-+ (struct usb_descriptor_header *) &za_14,
-+ (struct usb_descriptor_header *) &za_15,
-+ (struct usb_descriptor_header *) &za_16,
-+ (struct usb_descriptor_header *) &za_17,
-+ (struct usb_descriptor_header *) &za_18,
-+ (struct usb_descriptor_header *) &za_19,
-+ (struct usb_descriptor_header *) &za_20,
-+ (struct usb_descriptor_header *) &za_21,
-+ (struct usb_descriptor_header *) &za_22,
-+ (struct usb_descriptor_header *) &za_23,
-+ (struct usb_descriptor_header *) &za_24,
-+ NULL,
-+};
-+
-+/* maxpacket and other transfer characteristics vary by speed. */
-+#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-+
-+#else
-+
-+/* if there's no high speed support, maxpacket doesn't change. */
-+#define ep_desc(g,hs,fs) fs
-+
-+#endif /* !CONFIG_USB_GADGET_DUALSPEED */
-+
-+static char manufacturer [40];
-+//static char serial [40];
-+static char serial [] = "Ser 00 em";
-+
-+/* static strings, in UTF-8 */
-+static struct usb_string strings [] = {
-+ { STRING_MANUFACTURER, manufacturer, },
-+ { STRING_PRODUCT, longname, },
-+ { STRING_SERIAL, serial, },
-+ { STRING_LOOPBACK, loopback, },
-+ { STRING_SOURCE_SINK, source_sink, },
-+ { } /* end of list */
-+};
-+
-+static struct usb_gadget_strings stringtab = {
-+ .language = 0x0409, /* en-us */
-+ .strings = strings,
-+};
-+
-+/*
-+ * config descriptors are also handcrafted. these must agree with code
-+ * that sets configurations, and with code managing interfaces and their
-+ * altsettings. other complexity may come from:
-+ *
-+ * - high speed support, including "other speed config" rules
-+ * - multiple configurations
-+ * - interfaces with alternate settings
-+ * - embedded class or vendor-specific descriptors
-+ *
-+ * this handles high speed, and has a second config that could as easily
-+ * have been an alternate interface setting (on most hardware).
-+ *
-+ * NOTE: to demonstrate (and test) more USB capabilities, this driver
-+ * should include an altsetting to test interrupt transfers, including
-+ * high bandwidth modes at high speed. (Maybe work like Intel's test
-+ * device?)
-+ */
-+static int
-+config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
-+{
-+ int len;
-+ const struct usb_descriptor_header **function;
-+
-+ function = z_function;
-+ len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
-+ if (len < 0)
-+ return len;
-+ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
-+ return len;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static struct usb_request *
-+alloc_ep_req (struct usb_ep *ep, unsigned length)
-+{
-+ struct usb_request *req;
-+
-+ req = usb_ep_alloc_request (ep, GFP_ATOMIC);
-+ if (req) {
-+ req->length = length;
-+ req->buf = usb_ep_alloc_buffer (ep, length,
-+ &req->dma, GFP_ATOMIC);
-+ if (!req->buf) {
-+ usb_ep_free_request (ep, req);
-+ req = NULL;
-+ }
-+ }
-+ return req;
-+}
-+
-+static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
-+{
-+ if (req->buf)
-+ usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
-+ usb_ep_free_request (ep, req);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* optionally require specific source/sink data patterns */
-+
-+static int
-+check_read_data (
-+ struct zero_dev *dev,
-+ struct usb_ep *ep,
-+ struct usb_request *req
-+)
-+{
-+ unsigned i;
-+ u8 *buf = req->buf;
-+
-+ for (i = 0; i < req->actual; i++, buf++) {
-+ switch (pattern) {
-+ /* all-zeroes has no synchronization issues */
-+ case 0:
-+ if (*buf == 0)
-+ continue;
-+ break;
-+ /* mod63 stays in sync with short-terminated transfers,
-+ * or otherwise when host and gadget agree on how large
-+ * each usb transfer request should be. resync is done
-+ * with set_interface or set_config.
-+ */
-+ case 1:
-+ if (*buf == (u8)(i % 63))
-+ continue;
-+ break;
-+ }
-+ ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
-+ usb_ep_set_halt (ep);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void zero_reset_config (struct zero_dev *dev)
-+{
-+ if (dev->config == 0)
-+ return;
-+
-+ DBG (dev, "reset config\n");
-+
-+ /* just disable endpoints, forcing completion of pending i/o.
-+ * all our completion handlers free their requests in this case.
-+ */
-+ if (dev->in_ep) {
-+ usb_ep_disable (dev->in_ep);
-+ dev->in_ep = NULL;
-+ }
-+ if (dev->out_ep) {
-+ usb_ep_disable (dev->out_ep);
-+ dev->out_ep = NULL;
-+ }
-+ dev->config = 0;
-+ del_timer (&dev->resume);
-+}
-+
-+#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
-+
-+static void
-+zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
-+{
-+ struct zero_dev *dev = ep->driver_data;
-+ int status = req->status;
-+ int i, j;
-+
-+ switch (status) {
-+
-+ case 0: /* normal completion? */
-+ //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
-+ for (i=0, j=rbuf_start; i<req->actual; i++) {
-+ //printk ("%02x ", ((__u8*)req->buf)[i]);
-+ rbuf[j] = ((__u8*)req->buf)[i];
-+ j++;
-+ if (j >= RBUF_LEN) j=0;
-+ }
-+ rbuf_start = j;
-+ //printk ("\n\n");
-+
-+ if (rbuf_len < RBUF_LEN) {
-+ rbuf_len += req->actual;
-+ if (rbuf_len > RBUF_LEN) {
-+ rbuf_len = RBUF_LEN;
-+ }
-+ }
-+
-+ break;
-+
-+ /* this endpoint is normally active while we're configured */
-+ case -ECONNABORTED: /* hardware forced ep reset */
-+ case -ECONNRESET: /* request dequeued */
-+ case -ESHUTDOWN: /* disconnect from host */
-+ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
-+ req->actual, req->length);
-+ if (ep == dev->out_ep)
-+ check_read_data (dev, ep, req);
-+ free_ep_req (ep, req);
-+ return;
-+
-+ case -EOVERFLOW: /* buffer overrun on read means that
-+ * we didn't provide a big enough
-+ * buffer.
-+ */
-+ default:
-+#if 1
-+ DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
-+ status, req->actual, req->length);
-+#endif
-+ case -EREMOTEIO: /* short read */
-+ break;
-+ }
-+
-+ status = usb_ep_queue (ep, req, GFP_ATOMIC);
-+ if (status) {
-+ ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
-+ ep->name, req->length, status);
-+ usb_ep_set_halt (ep);
-+ /* FIXME recover later ... somehow */
-+ }
-+}
-+
-+static struct usb_request *
-+zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
-+{
-+ struct usb_request *req;
-+ int status;
-+
-+ req = alloc_ep_req (ep, 512);
-+ if (!req)
-+ return NULL;
-+
-+ req->complete = zero_isoc_complete;
-+
-+ status = usb_ep_queue (ep, req, gfp_flags);
-+ if (status) {
-+ struct zero_dev *dev = ep->driver_data;
-+
-+ ERROR (dev, "start %s --> %d\n", ep->name, status);
-+ free_ep_req (ep, req);
-+ req = NULL;
-+ }
-+
-+ return req;
-+}
-+
-+/* change our operational config. this code must agree with the code
-+ * that returns config descriptors, and altsetting code.
-+ *
-+ * it's also responsible for power management interactions. some
-+ * configurations might not work with our current power sources.
-+ *
-+ * note that some device controller hardware will constrain what this
-+ * code can do, perhaps by disallowing more than one configuration or
-+ * by limiting configuration choices (like the pxa2xx).
-+ */
-+static int
-+zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
-+{
-+ int result = 0;
-+ struct usb_gadget *gadget = dev->gadget;
-+ const struct usb_endpoint_descriptor *d;
-+ struct usb_ep *ep;
-+
-+ if (number == dev->config)
-+ return 0;
-+
-+ zero_reset_config (dev);
-+
-+ gadget_for_each_ep (ep, gadget) {
-+
-+ if (strcmp (ep->name, "ep4") == 0) {
-+
-+ d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
-+ result = usb_ep_enable (ep, d);
-+
-+ if (result == 0) {
-+ ep->driver_data = dev;
-+ dev->in_ep = ep;
-+
-+ if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
-+
-+ dev->in_ep = ep;
-+ continue;
-+ }
-+
-+ usb_ep_disable (ep);
-+ result = -EIO;
-+ }
-+ }
-+
-+ }
-+
-+ dev->config = number;
-+ return result;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
-+{
-+ if (req->status || req->actual != req->length)
-+ DBG ((struct zero_dev *) ep->driver_data,
-+ "setup complete --> %d, %d/%d\n",
-+ req->status, req->actual, req->length);
-+}
-+
-+/*
-+ * The setup() callback implements all the ep0 functionality that's
-+ * not handled lower down, in hardware or the hardware driver (like
-+ * device and endpoint feature flags, and their status). It's all
-+ * housekeeping for the gadget function we're implementing. Most of
-+ * the work is in config-specific setup.
-+ */
-+static int
-+zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
-+{
-+ struct zero_dev *dev = get_gadget_data (gadget);
-+ struct usb_request *req = dev->req;
-+ int value = -EOPNOTSUPP;
-+
-+ /* usually this stores reply data in the pre-allocated ep0 buffer,
-+ * but config change events will reconfigure hardware.
-+ */
-+ req->zero = 0;
-+ switch (ctrl->bRequest) {
-+
-+ case USB_REQ_GET_DESCRIPTOR:
-+
-+ switch (ctrl->wValue >> 8) {
-+
-+ case USB_DT_DEVICE:
-+ value = min (ctrl->wLength, (u16) sizeof device_desc);
-+ memcpy (req->buf, &device_desc, value);
-+ break;
-+#ifdef CONFIG_USB_GADGET_DUALSPEED
-+ case USB_DT_DEVICE_QUALIFIER:
-+ if (!gadget->is_dualspeed)
-+ break;
-+ value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
-+ memcpy (req->buf, &dev_qualifier, value);
-+ break;
-+
-+ case USB_DT_OTHER_SPEED_CONFIG:
-+ if (!gadget->is_dualspeed)
-+ break;
-+ // FALLTHROUGH
-+#endif /* CONFIG_USB_GADGET_DUALSPEED */
-+ case USB_DT_CONFIG:
-+ value = config_buf (gadget, req->buf,
-+ ctrl->wValue >> 8,
-+ ctrl->wValue & 0xff);
-+ if (value >= 0)
-+ value = min (ctrl->wLength, (u16) value);
-+ break;
-+
-+ case USB_DT_STRING:
-+ /* wIndex == language code.
-+ * this driver only handles one language, you can
-+ * add string tables for other languages, using
-+ * any UTF-8 characters
-+ */
-+ value = usb_gadget_get_string (&stringtab,
-+ ctrl->wValue & 0xff, req->buf);
-+ if (value >= 0) {
-+ value = min (ctrl->wLength, (u16) value);
-+ }
-+ break;
-+ }
-+ break;
-+
-+ /* currently two configs, two speeds */
-+ case USB_REQ_SET_CONFIGURATION:
-+ if (ctrl->bRequestType != 0)
-+ goto unknown;
-+
-+ spin_lock (&dev->lock);
-+ value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
-+ spin_unlock (&dev->lock);
-+ break;
-+ case USB_REQ_GET_CONFIGURATION:
-+ if (ctrl->bRequestType != USB_DIR_IN)
-+ goto unknown;
-+ *(u8 *)req->buf = dev->config;
-+ value = min (ctrl->wLength, (u16) 1);
-+ break;
-+
-+ /* until we add altsetting support, or other interfaces,
-+ * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
-+ * and already killed pending endpoint I/O.
-+ */
-+ case USB_REQ_SET_INTERFACE:
-+
-+ if (ctrl->bRequestType != USB_RECIP_INTERFACE)
-+ goto unknown;
-+ spin_lock (&dev->lock);
-+ if (dev->config) {
-+ u8 config = dev->config;
-+
-+ /* resets interface configuration, forgets about
-+ * previous transaction state (queued bufs, etc)
-+ * and re-inits endpoint state (toggle etc)
-+ * no response queued, just zero status == success.
-+ * if we had more than one interface we couldn't
-+ * use this "reset the config" shortcut.
-+ */
-+ zero_reset_config (dev);
-+ zero_set_config (dev, config, GFP_ATOMIC);
-+ value = 0;
-+ }
-+ spin_unlock (&dev->lock);
-+ break;
-+ case USB_REQ_GET_INTERFACE:
-+ if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
-+ value = ctrl->wLength;
-+ break;
-+ }
-+ else {
-+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
-+ goto unknown;
-+ if (!dev->config)
-+ break;
-+ if (ctrl->wIndex != 0) {
-+ value = -EDOM;
-+ break;
-+ }
-+ *(u8 *)req->buf = 0;
-+ value = min (ctrl->wLength, (u16) 1);
-+ }
-+ break;
-+
-+ /*
-+ * These are the same vendor-specific requests supported by
-+ * Intel's USB 2.0 compliance test devices. We exceed that
-+ * device spec by allowing multiple-packet requests.
-+ */
-+ case 0x5b: /* control WRITE test -- fill the buffer */
-+ if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
-+ goto unknown;
-+ if (ctrl->wValue || ctrl->wIndex)
-+ break;
-+ /* just read that many bytes into the buffer */
-+ if (ctrl->wLength > USB_BUFSIZ)
-+ break;
-+ value = ctrl->wLength;
-+ break;
-+ case 0x5c: /* control READ test -- return the buffer */
-+ if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
-+ goto unknown;
-+ if (ctrl->wValue || ctrl->wIndex)
-+ break;
-+ /* expect those bytes are still in the buffer; send back */
-+ if (ctrl->wLength > USB_BUFSIZ
-+ || ctrl->wLength != req->length)
-+ break;
-+ value = ctrl->wLength;
-+ break;
-+
-+ case 0x01: // SET_CUR
-+ case 0x02:
-+ case 0x03:
-+ case 0x04:
-+ case 0x05:
-+ value = ctrl->wLength;
-+ break;
-+ case 0x81:
-+ switch (ctrl->wValue) {
-+ case 0x0201:
-+ case 0x0202:
-+ ((u8*)req->buf)[0] = 0x00;
-+ ((u8*)req->buf)[1] = 0xe3;
-+ break;
-+ case 0x0300:
-+ case 0x0500:
-+ ((u8*)req->buf)[0] = 0x00;
-+ break;
-+ }
-+ //((u8*)req->buf)[0] = 0x81;
-+ //((u8*)req->buf)[1] = 0x81;
-+ value = ctrl->wLength;
-+ break;
-+ case 0x82:
-+ switch (ctrl->wValue) {
-+ case 0x0201:
-+ case 0x0202:
-+ ((u8*)req->buf)[0] = 0x00;
-+ ((u8*)req->buf)[1] = 0xc3;
-+ break;
-+ case 0x0300:
-+ case 0x0500:
-+ ((u8*)req->buf)[0] = 0x00;
-+ break;
-+ }
-+ //((u8*)req->buf)[0] = 0x82;
-+ //((u8*)req->buf)[1] = 0x82;
-+ value = ctrl->wLength;
-+ break;
-+ case 0x83:
-+ switch (ctrl->wValue) {
-+ case 0x0201:
-+ case 0x0202:
-+ ((u8*)req->buf)[0] = 0x00;
-+ ((u8*)req->buf)[1] = 0x00;
-+ break;
-+ case 0x0300:
-+ ((u8*)req->buf)[0] = 0x60;
-+ break;
-+ case 0x0500:
-+ ((u8*)req->buf)[0] = 0x18;
-+ break;
-+ }
-+ //((u8*)req->buf)[0] = 0x83;
-+ //((u8*)req->buf)[1] = 0x83;
-+ value = ctrl->wLength;
-+ break;
-+ case 0x84:
-+ switch (ctrl->wValue) {
-+ case 0x0201:
-+ case 0x0202:
-+ ((u8*)req->buf)[0] = 0x00;
-+ ((u8*)req->buf)[1] = 0x01;
-+ break;
-+ case 0x0300:
-+ case 0x0500:
-+ ((u8*)req->buf)[0] = 0x08;
-+ break;
-+ }
-+ //((u8*)req->buf)[0] = 0x84;
-+ //((u8*)req->buf)[1] = 0x84;
-+ value = ctrl->wLength;
-+ break;
-+ case 0x85:
-+ ((u8*)req->buf)[0] = 0x85;
-+ ((u8*)req->buf)[1] = 0x85;
-+ value = ctrl->wLength;
-+ break;
-+
-+
-+ default:
-+unknown:
-+ printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
-+ ctrl->bRequestType, ctrl->bRequest,
-+ ctrl->wValue, ctrl->wIndex, ctrl->wLength);
-+ }
-+
-+ /* respond with data transfer before status phase? */
-+ if (value >= 0) {
-+ req->length = value;
-+ req->zero = value < ctrl->wLength
-+ && (value % gadget->ep0->maxpacket) == 0;
-+ value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
-+ if (value < 0) {
-+ DBG (dev, "ep_queue < 0 --> %d\n", value);
-+ req->status = 0;
-+ zero_setup_complete (gadget->ep0, req);
-+ }
-+ }
-+
-+ /* device either stalls (value < 0) or reports success */
-+ return value;
-+}
-+
-+static void
-+zero_disconnect (struct usb_gadget *gadget)
-+{
-+ struct zero_dev *dev = get_gadget_data (gadget);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave (&dev->lock, flags);
-+ zero_reset_config (dev);
-+
-+ /* a more significant application might have some non-usb
-+ * activities to quiesce here, saving resources like power
-+ * or pushing the notification up a network stack.
-+ */
-+ spin_unlock_irqrestore (&dev->lock, flags);
-+
-+ /* next we may get setup() calls to enumerate new connections;
-+ * or an unbind() during shutdown (including removing module).
-+ */
-+}
-+
-+static void
-+zero_autoresume (unsigned long _dev)
-+{
-+ struct zero_dev *dev = (struct zero_dev *) _dev;
-+ int status;
-+
-+ /* normally the host would be woken up for something
-+ * more significant than just a timer firing...
-+ */
-+ if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
-+ status = usb_gadget_wakeup (dev->gadget);
-+ DBG (dev, "wakeup --> %d\n", status);
-+ }
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void
-+zero_unbind (struct usb_gadget *gadget)
-+{
-+ struct zero_dev *dev = get_gadget_data (gadget);
-+
-+ DBG (dev, "unbind\n");
-+
-+ /* we've already been disconnected ... no i/o is active */
-+ if (dev->req)
-+ free_ep_req (gadget->ep0, dev->req);
-+ del_timer_sync (&dev->resume);
-+ kfree (dev);
-+ set_gadget_data (gadget, NULL);
-+}
-+
-+static int
-+zero_bind (struct usb_gadget *gadget)
-+{
-+ struct zero_dev *dev;
-+ //struct usb_ep *ep;
-+
-+ printk("binding\n");
-+ /*
-+ * DRIVER POLICY CHOICE: you may want to do this differently.
-+ * One thing to avoid is reusing a bcdDevice revision code
-+ * with different host-visible configurations or behavior
-+ * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
-+ */
-+ //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
-+
-+
-+ /* ok, we made sense of the hardware ... */
-+ dev = kmalloc (sizeof *dev, SLAB_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+ memset (dev, 0, sizeof *dev);
-+ spin_lock_init (&dev->lock);
-+ dev->gadget = gadget;
-+ set_gadget_data (gadget, dev);
-+
-+ /* preallocate control response and buffer */
-+ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
-+ if (!dev->req)
-+ goto enomem;
-+ dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
-+ &dev->req->dma, GFP_KERNEL);
-+ if (!dev->req->buf)
-+ goto enomem;
-+
-+ dev->req->complete = zero_setup_complete;
-+
-+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-+
-+#ifdef CONFIG_USB_GADGET_DUALSPEED
-+ /* assume ep0 uses the same value for both speeds ... */
-+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
-+
-+ /* and that all endpoints are dual-speed */
-+ //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-+ //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-+#endif
-+
-+ usb_gadget_set_selfpowered (gadget);
-+
-+ init_timer (&dev->resume);
-+ dev->resume.function = zero_autoresume;
-+ dev->resume.data = (unsigned long) dev;
-+
-+ gadget->ep0->driver_data = dev;
-+
-+ INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
-+ INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
-+ EP_OUT_NAME, EP_IN_NAME);
-+
-+ snprintf (manufacturer, sizeof manufacturer,
-+ UTS_SYSNAME " " UTS_RELEASE " with %s",
-+ gadget->name);
-+
-+ return 0;
-+
-+enomem:
-+ zero_unbind (gadget);
-+ return -ENOMEM;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void
-+zero_suspend (struct usb_gadget *gadget)
-+{
-+ struct zero_dev *dev = get_gadget_data (gadget);
-+
-+ if (gadget->speed == USB_SPEED_UNKNOWN)
-+ return;
-+
-+ if (autoresume) {
-+ mod_timer (&dev->resume, jiffies + (HZ * autoresume));
-+ DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
-+ } else
-+ DBG (dev, "suspend\n");
-+}
-+
-+static void
-+zero_resume (struct usb_gadget *gadget)
-+{
-+ struct zero_dev *dev = get_gadget_data (gadget);
-+
-+ DBG (dev, "resume\n");
-+ del_timer (&dev->resume);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static struct usb_gadget_driver zero_driver = {
-+#ifdef CONFIG_USB_GADGET_DUALSPEED
-+ .speed = USB_SPEED_HIGH,
-+#else
-+ .speed = USB_SPEED_FULL,
-+#endif
-+ .function = (char *) longname,
-+ .bind = zero_bind,
-+ .unbind = zero_unbind,
-+
-+ .setup = zero_setup,
-+ .disconnect = zero_disconnect,
-+
-+ .suspend = zero_suspend,
-+ .resume = zero_resume,
-+
-+ .driver = {
-+ .name = (char *) shortname,
-+ // .shutdown = ...
-+ // .suspend = ...
-+ // .resume = ...
-+ },
-+};
-+
-+MODULE_AUTHOR ("David Brownell");
-+MODULE_LICENSE ("Dual BSD/GPL");
-+
-+static struct proc_dir_entry *pdir, *pfile;
-+
-+static int isoc_read_data (char *page, char **start,
-+ off_t off, int count,
-+ int *eof, void *data)
-+{
-+ int i;
-+ static int c = 0;
-+ static int done = 0;
-+ static int s = 0;
-+
-+/*
-+ printk ("\ncount: %d\n", count);
-+ printk ("rbuf_start: %d\n", rbuf_start);
-+ printk ("rbuf_len: %d\n", rbuf_len);
-+ printk ("off: %d\n", off);
-+ printk ("start: %p\n\n", *start);
-+*/
-+ if (done) {
-+ c = 0;
-+ done = 0;
-+ *eof = 1;
-+ return 0;
-+ }
-+
-+ if (c == 0) {
-+ if (rbuf_len == RBUF_LEN)
-+ s = rbuf_start;
-+ else s = 0;
-+ }
-+
-+ for (i=0; i<count && c<rbuf_len; i++, c++) {
-+ page[i] = rbuf[(c+s) % RBUF_LEN];
-+ }
-+ *start = page;
-+
-+ if (c >= rbuf_len) {
-+ *eof = 1;
-+ done = 1;
-+ }
-+
-+
-+ return i;
-+}
-+
-+static int __init init (void)
-+{
-+
-+ int retval = 0;
-+
-+ pdir = proc_mkdir("isoc_test", NULL);
-+ if(pdir == NULL) {
-+ retval = -ENOMEM;
-+ printk("Error creating dir\n");
-+ goto done;
-+ }
-+ pdir->owner = THIS_MODULE;
-+
-+ pfile = create_proc_read_entry("isoc_data",
-+ 0444, pdir,
-+ isoc_read_data,
-+ NULL);
-+ if (pfile == NULL) {
-+ retval = -ENOMEM;
-+ printk("Error creating file\n");
-+ goto no_file;
-+ }
-+ pfile->owner = THIS_MODULE;
-+
-+ return usb_gadget_register_driver (&zero_driver);
-+
-+ no_file:
-+ remove_proc_entry("isoc_data", NULL);
-+ done:
-+ return retval;
-+}
-+module_init (init);
-+
-+static void __exit cleanup (void)
-+{
-+
-+ usb_gadget_unregister_driver (&zero_driver);
-+
-+ remove_proc_entry("isoc_data", pdir);
-+ remove_proc_entry("isoc_test", NULL);
-+}
-+module_exit (cleanup);
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_cfi_common.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_cfi_common.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_cfi_common.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_cfi_common.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,142 @@
-+/* ==========================================================================
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#if !defined(__DWC_CFI_COMMON_H__)
-+#define __DWC_CFI_COMMON_H__
-+
-+//#include <linux/types.h>
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the CFI specific common constants, interfaces
-+ * (functions and macros) and structures for Linux. No PCD specific
-+ * data structure or definition is to be included in this file.
-+ *
-+ */
-+
-+/** This is a request for all Core Features */
-+#define VEN_CORE_GET_FEATURES 0xB1
-+
-+/** This is a request to get the value of a specific Core Feature */
-+#define VEN_CORE_GET_FEATURE 0xB2
-+
-+/** This command allows the host to set the value of a specific Core Feature */
-+#define VEN_CORE_SET_FEATURE 0xB3
-+
-+/** This command allows the host to set the default values of
-+ * either all or any specific Core Feature
-+ */
-+#define VEN_CORE_RESET_FEATURES 0xB4
-+
-+/** This command forces the PCD to write the deferred values of a Core Features */
-+#define VEN_CORE_ACTIVATE_FEATURES 0xB5
-+
-+/** This request reads a DWORD value from a register at the specified offset */
-+#define VEN_CORE_READ_REGISTER 0xB6
-+
-+/** This request writes a DWORD value into a register at the specified offset */
-+#define VEN_CORE_WRITE_REGISTER 0xB7
-+
-+/** This structure is the header of the Core Features dataset returned to
-+ * the Host
-+ */
-+struct cfi_all_features_header {
-+/** The features header structure length is */
-+#define CFI_ALL_FEATURES_HDR_LEN 8
-+ /**
-+ * The total length of the features dataset returned to the Host
-+ */
-+ uint16_t wTotalLen;
-+
-+ /**
-+ * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
-+ * This field identifies the version of the CFI Specification with which
-+ * the device is compliant.
-+ */
-+ uint16_t wVersion;
-+
-+ /** The ID of the Core */
-+ uint16_t wCoreID;
-+#define CFI_CORE_ID_UDC 1
-+#define CFI_CORE_ID_OTG 2
-+#define CFI_CORE_ID_WUDEV 3
-+
-+ /** Number of features returned by VEN_CORE_GET_FEATURES request */
-+ uint16_t wNumFeatures;
-+} UPACKED;
-+
-+typedef struct cfi_all_features_header cfi_all_features_header_t;
-+
-+/** This structure is a header of the Core Feature descriptor dataset returned to
-+ * the Host after the VEN_CORE_GET_FEATURES request
-+ */
-+struct cfi_feature_desc_header {
-+#define CFI_FEATURE_DESC_HDR_LEN 8
-+
-+ /** The feature ID */
-+ uint16_t wFeatureID;
-+
-+ /** Length of this feature descriptor in bytes - including the
-+ * length of the feature name string
-+ */
-+ uint16_t wLength;
-+
-+ /** The data length of this feature in bytes */
-+ uint16_t wDataLength;
-+
-+ /**
-+ * Attributes of this features
-+ * D0: Access rights
-+ * 0 - Read/Write
-+ * 1 - Read only
-+ */
-+ uint8_t bmAttributes;
-+#define CFI_FEATURE_ATTR_RO 1
-+#define CFI_FEATURE_ATTR_RW 0
-+
-+ /** Length of the feature name in bytes */
-+ uint8_t bNameLen;
-+
-+ /** The feature name buffer */
-+ //uint8_t *name;
-+} UPACKED;
-+
-+typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
-+
-+/**
-+ * This structure describes a NULL terminated string referenced by its id field.
-+ * It is very similar to usb_string structure but has the id field type set to 16-bit.
-+ */
-+struct cfi_string {
-+ uint16_t id;
-+ const uint8_t *s;
-+};
-+typedef struct cfi_string cfi_string_t;
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_adp.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_adp.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_adp.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_adp.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,854 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
-+ * $Revision: #12 $
-+ * $Date: 2011/10/26 $
-+ * $Change: 1873028 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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 "dwc_os.h"
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_cil.h"
-+#include "dwc_otg_adp.h"
-+
-+/** @file
-+ *
-+ * This file contains the most of the Attach Detect Protocol implementation for
-+ * the driver to support OTG Rev2.0.
-+ *
-+ */
-+
-+void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
-+{
-+ adpctl_data_t adpctl;
-+
-+ adpctl.d32 = value;
-+ adpctl.b.ar = 0x2;
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
-+
-+ while (adpctl.b.ar) {
-+ adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
-+ }
-+
-+}
-+
-+/**
-+ * Function is called to read ADP registers
-+ */
-+uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
-+{
-+ adpctl_data_t adpctl;
-+
-+ adpctl.d32 = 0;
-+ adpctl.b.ar = 0x1;
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
-+
-+ while (adpctl.b.ar) {
-+ adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
-+ }
-+
-+ return adpctl.d32;
-+}
-+
-+/**
-+ * Function is called to read ADPCTL register and filter Write-clear bits
-+ */
-+uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
-+{
-+ adpctl_data_t adpctl;
-+
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ adpctl.b.adp_tmout_int = 0;
-+ adpctl.b.adp_prb_int = 0;
-+ adpctl.b.adp_tmout_int = 0;
-+
-+ return adpctl.d32;
-+}
-+
-+/**
-+ * Function is called to write ADP registers
-+ */
-+void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
-+ uint32_t set)
-+{
-+ dwc_otg_adp_write_reg(core_if,
-+ (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
-+}
-+
-+static void adp_sense_timeout(void *ptr)
-+{
-+ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
-+ core_if->adp.sense_timer_started = 0;
-+ DWC_PRINTF("ADP SENSE TIMEOUT\n");
-+ if (core_if->adp_enable) {
-+ dwc_otg_adp_sense_stop(core_if);
-+ dwc_otg_adp_probe_start(core_if);
-+ }
-+}
-+
-+/**
-+ * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
-+ */
-+static void adp_vbuson_timeout(void *ptr)
-+{
-+ gpwrdn_data_t gpwrdn;
-+ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
-+ if (core_if) {
-+ core_if->adp.vbuson_timer_started = 0;
-+ /* Turn off vbus */
-+ hprt0.b.prtpwr = 1;
-+ DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
-+ gpwrdn.d32 = 0;
-+
-+ /* Power off the core */
-+ if (core_if->power_down == 2) {
-+ /* Enable Wakeup Logic */
-+// gpwrdn.b.wkupactiv = 1;
-+ gpwrdn.b.pmuactv = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
-+ gpwrdn.d32);
-+
-+ /* Suspend the Phy Clock */
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
-+
-+ /* Switch on VDD */
-+// gpwrdn.b.wkupactiv = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
-+ gpwrdn.d32);
-+ } else {
-+ /* Enable Power Down Logic */
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ }
-+
-+ /* Power off the core */
-+ if (core_if->power_down == 2) {
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
-+ gpwrdn.d32, 0);
-+ }
-+
-+ /* Unmask SRP detected interrupt from Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.srp_det_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+
-+ dwc_otg_adp_probe_start(core_if);
-+ dwc_otg_dump_global_registers(core_if);
-+ dwc_otg_dump_host_registers(core_if);
-+ }
-+
-+}
-+
-+/**
-+ * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
-+ * not asserted within 1.1 seconds.
-+ *
-+ * @param core_if the pointer to core_if strucure.
-+ */
-+void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
-+{
-+ core_if->adp.vbuson_timer_started = 1;
-+ if (core_if->adp.vbuson_timer)
-+ {
-+ DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
-+ /* 1.1 secs + 60ms necessary for cil_hcd_start*/
-+ DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
-+ } else {
-+ DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
-+ }
-+}
-+
-+#if 0
-+/**
-+ * Masks all DWC OTG core interrupts
-+ *
-+ */
-+static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ int i;
-+ gahbcfg_data_t ahbcfg = {.d32 = 0 };
-+
-+ /* Mask Host Interrupts */
-+
-+ /* Clear and disable HCINTs */
-+ for (i = 0; i < core_if->core_params->host_channels; i++) {
-+ DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
-+ DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
-+
-+ }
-+
-+ /* Clear and disable HAINT */
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
-+
-+ /* Mask Device Interrupts */
-+ if (!core_if->multiproc_int_enable) {
-+ /* Clear and disable IN Endpoint interrupts */
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
-+ for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
-+ diepint, 0xFFFFFFFF);
-+ }
-+
-+ /* Clear and disable OUT Endpoint interrupts */
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
-+ for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
-+ doepint, 0xFFFFFFFF);
-+ }
-+
-+ /* Clear and disable DAINT */
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
-+ 0xFFFFFFFF);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
-+ } else {
-+ for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
-+ diepeachintmsk[i], 0);
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
-+ diepint, 0xFFFFFFFF);
-+ }
-+
-+ for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
-+ doepeachintmsk[i], 0);
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
-+ doepint, 0xFFFFFFFF);
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
-+ 0);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
-+ 0xFFFFFFFF);
-+
-+ }
-+
-+ /* Disable interrupts */
-+ ahbcfg.b.glblintrmsk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
-+
-+ /* Disable all interrupts. */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
-+
-+ /* Clear any pending interrupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* Clear any pending OTG Interrupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
-+}
-+
-+/**
-+ * Unmask Port Connection Detected interrupt
-+ *
-+ */
-+static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
-+}
-+#endif
-+
-+/**
-+ * Starts the ADP Probing
-+ *
-+ * @param core_if the pointer to core_if structure.
-+ */
-+uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
-+{
-+
-+ adpctl_data_t adpctl = {.d32 = 0};
-+ gpwrdn_data_t gpwrdn;
-+#if 0
-+ adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
-+ .b.adp_sns_int = 1, b.adp_tmout_int};
-+#endif
-+ dwc_otg_disable_global_interrupts(core_if);
-+ DWC_PRINTF("ADP Probe Start\n");
-+ core_if->adp.probe_enabled = 1;
-+
-+ adpctl.b.adpres = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ while (adpctl.b.adpres) {
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ }
-+
-+ adpctl.d32 = 0;
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+
-+ /* In Host mode unmask SRP detected interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.sts_chngint_msk = 1;
-+ if (!gpwrdn.b.idsts) {
-+ gpwrdn.b.srp_det_msk = 1;
-+ }
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+
-+ adpctl.b.adp_tmout_int_msk = 1;
-+ adpctl.b.adp_prb_int_msk = 1;
-+ adpctl.b.prb_dschg = 1;
-+ adpctl.b.prb_delta = 1;
-+ adpctl.b.prb_per = 1;
-+ adpctl.b.adpen = 1;
-+ adpctl.b.enaprb = 1;
-+
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+ DWC_PRINTF("ADP Probe Finish\n");
-+ return 0;
-+}
-+
-+/**
-+ * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
-+ * within 3 seconds.
-+ *
-+ * @param core_if the pointer to core_if strucure.
-+ */
-+void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
-+{
-+ core_if->adp.sense_timer_started = 1;
-+ DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
-+}
-+
-+/**
-+ * Starts the ADP Sense
-+ *
-+ * @param core_if the pointer to core_if strucure.
-+ */
-+uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
-+{
-+ adpctl_data_t adpctl;
-+
-+ DWC_PRINTF("ADP Sense Start\n");
-+
-+ /* Unmask ADP sense interrupt and mask all other from the core */
-+ adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
-+ adpctl.b.adp_sns_int_msk = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+ dwc_otg_disable_global_interrupts(core_if); // vahrama
-+
-+ /* Set ADP reset bit*/
-+ adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
-+ adpctl.b.adpres = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ while (adpctl.b.adpres) {
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ }
-+
-+ adpctl.b.adpres = 0;
-+ adpctl.b.adpen = 1;
-+ adpctl.b.enasns = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ dwc_otg_adp_sense_timer_start(core_if);
-+
-+ return 0;
-+}
-+
-+/**
-+ * Stops the ADP Probing
-+ *
-+ * @param core_if the pointer to core_if strucure.
-+ */
-+uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
-+{
-+
-+ adpctl_data_t adpctl;
-+ DWC_PRINTF("Stop ADP probe\n");
-+ core_if->adp.probe_enabled = 0;
-+ core_if->adp.probe_counter = 0;
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+
-+ adpctl.b.adpen = 0;
-+ adpctl.b.adp_prb_int = 1;
-+ adpctl.b.adp_tmout_int = 1;
-+ adpctl.b.adp_sns_int = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ return 0;
-+}
-+
-+/**
-+ * Stops the ADP Sensing
-+ *
-+ * @param core_if the pointer to core_if strucure.
-+ */
-+uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
-+{
-+ adpctl_data_t adpctl;
-+
-+ core_if->adp.sense_enabled = 0;
-+
-+ adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
-+ adpctl.b.enasns = 0;
-+ adpctl.b.adp_sns_int = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ return 0;
-+}
-+
-+/**
-+ * Called to turn on the VBUS after initial ADP probe in host mode.
-+ * If port power was already enabled in cil_hcd_start function then
-+ * only schedule a timer.
-+ *
-+ * @param core_if the pointer to core_if structure.
-+ */
-+void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
-+{
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
-+
-+ if (hprt0.b.prtpwr == 0) {
-+ hprt0.b.prtpwr = 1;
-+ //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ }
-+
-+ dwc_otg_adp_vbuson_timer_start(core_if);
-+}
-+
-+/**
-+ * Called right after driver is loaded
-+ * to perform initial actions for ADP
-+ *
-+ * @param core_if the pointer to core_if structure.
-+ * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
-+ */
-+void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
-+{
-+ gpwrdn_data_t gpwrdn;
-+
-+ DWC_PRINTF("ADP Initial Start\n");
-+ core_if->adp.adp_started = 1;
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+ dwc_otg_disable_global_interrupts(core_if);
-+ if (is_host) {
-+ DWC_PRINTF("HOST MODE\n");
-+ /* Enable Power Down Logic Interrupt*/
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ /* Initialize first ADP probe to obtain Ramp Time value */
-+ core_if->adp.initial_probe = 1;
-+ dwc_otg_adp_probe_start(core_if);
-+ } else {
-+ gotgctl_data_t gotgctl;
-+ gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ DWC_PRINTF("DEVICE MODE\n");
-+ if (gotgctl.b.bsesvld == 0) {
-+ /* Enable Power Down Logic Interrupt*/
-+ gpwrdn.d32 = 0;
-+ DWC_PRINTF("VBUS is not valid - start ADP probe\n");
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ core_if->adp.initial_probe = 1;
-+ dwc_otg_adp_probe_start(core_if);
-+ } else {
-+ DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ dwc_otg_dump_global_registers(core_if);
-+ dwc_otg_dump_dev_registers(core_if);
-+ }
-+ }
-+}
-+
-+void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
-+{
-+ core_if->adp.adp_started = 0;
-+ core_if->adp.initial_probe = 0;
-+ core_if->adp.probe_timer_values[0] = -1;
-+ core_if->adp.probe_timer_values[1] = -1;
-+ core_if->adp.probe_enabled = 0;
-+ core_if->adp.sense_enabled = 0;
-+ core_if->adp.sense_timer_started = 0;
-+ core_if->adp.vbuson_timer_started = 0;
-+ core_if->adp.probe_counter = 0;
-+ core_if->adp.gpwrdn = 0;
-+ core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
-+ /* Initialize timers */
-+ core_if->adp.sense_timer =
-+ DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
-+ core_if->adp.vbuson_timer =
-+ DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
-+ if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
-+ {
-+ DWC_ERROR("Could not allocate memory for ADP timers\n");
-+ }
-+}
-+
-+void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
-+{
-+ gpwrdn_data_t gpwrdn = { .d32 = 0 };
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ if (core_if->adp.probe_enabled)
-+ dwc_otg_adp_probe_stop(core_if);
-+ if (core_if->adp.sense_enabled)
-+ dwc_otg_adp_sense_stop(core_if);
-+ if (core_if->adp.sense_timer_started)
-+ DWC_TIMER_CANCEL(core_if->adp.sense_timer);
-+ if (core_if->adp.vbuson_timer_started)
-+ DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
-+ DWC_TIMER_FREE(core_if->adp.sense_timer);
-+ DWC_TIMER_FREE(core_if->adp.vbuson_timer);
-+}
-+
-+/////////////////////////////////////////////////////////////////////
-+////////////// ADP Interrupt Handlers ///////////////////////////////
-+/////////////////////////////////////////////////////////////////////
-+/**
-+ * This function sets Ramp Timer values
-+ */
-+static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ if (core_if->adp.probe_timer_values[0] == -1) {
-+ core_if->adp.probe_timer_values[0] = val;
-+ core_if->adp.probe_timer_values[1] = -1;
-+ return 1;
-+ } else {
-+ core_if->adp.probe_timer_values[1] =
-+ core_if->adp.probe_timer_values[0];
-+ core_if->adp.probe_timer_values[0] = val;
-+ return 0;
-+ }
-+}
-+
-+/**
-+ * This function compares Ramp Timer values
-+ */
-+static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t diff;
-+ if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
-+ diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
-+ else
-+ diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
-+ if(diff < 2) {
-+ return 0;
-+ } else {
-+ return 1;
-+ }
-+}
-+
-+/**
-+ * This function handles ADP Probe Interrupts
-+ */
-+static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
-+ uint32_t val)
-+{
-+ adpctl_data_t adpctl = {.d32 = 0 };
-+ gpwrdn_data_t gpwrdn, temp;
-+ adpctl.d32 = val;
-+
-+ temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ core_if->adp.probe_counter++;
-+ core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ if (adpctl.b.rtim == 0 && !temp.b.idsts){
-+ DWC_PRINTF("RTIM value is 0\n");
-+ goto exit;
-+ }
-+ if (set_timer_value(core_if, adpctl.b.rtim) &&
-+ core_if->adp.initial_probe) {
-+ core_if->adp.initial_probe = 0;
-+ dwc_otg_adp_probe_stop(core_if);
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* check which value is for device mode and which for Host mode */
-+ if (!temp.b.idsts) { /* considered host mode value is 0 */
-+ /*
-+ * Turn on VBUS after initial ADP probe.
-+ */
-+ core_if->op_state = A_HOST;
-+ dwc_otg_enable_global_interrupts(core_if);
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_hcd_start(core_if);
-+ dwc_otg_adp_turnon_vbus(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ } else {
-+ /*
-+ * Initiate SRP after initial ADP probe.
-+ */
-+ dwc_otg_enable_global_interrupts(core_if);
-+ dwc_otg_initiate_srp(core_if);
-+ }
-+ } else if (core_if->adp.probe_counter > 2){
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ if (compare_timer_values(core_if)) {
-+ DWC_PRINTF("Difference in timer values !!! \n");
-+// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
-+ dwc_otg_adp_probe_stop(core_if);
-+
-+ /* Power on the core */
-+ if (core_if->power_down == 2) {
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ }
-+
-+ /* check which value is for device mode and which for Host mode */
-+ if (!temp.b.idsts) { /* considered host mode value is 0 */
-+ /* Disable Interrupt from Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, gpwrdn.d32, 0);
-+
-+ /*
-+ * Initialize the Core for Host mode.
-+ */
-+ core_if->op_state = A_HOST;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+ } else {
-+ gotgctl_data_t gotgctl;
-+ /* Mask SRP detected interrupt from Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.srp_det_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Disable Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, gpwrdn.d32, 0);
-+
-+ /*
-+ * Initialize the Core for Device mode.
-+ */
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+
-+ gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ if (!gotgctl.b.bsesvld) {
-+ dwc_otg_initiate_srp(core_if);
-+ }
-+ }
-+ }
-+ if (core_if->power_down == 2) {
-+ if (gpwrdn.b.bsessvld) {
-+ /* Mask SRP detected interrupt from Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.srp_det_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Disable Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /*
-+ * Initialize the Core for Device mode.
-+ */
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ }
-+ }
-+ }
-+exit:
-+ /* Clear interrupt */
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ adpctl.b.adp_prb_int = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function hadles ADP Sense Interrupt
-+ */
-+static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
-+{
-+ adpctl_data_t adpctl;
-+ /* Stop ADP Sense timer */
-+ DWC_TIMER_CANCEL(core_if->adp.sense_timer);
-+
-+ /* Restart ADP Sense timer */
-+ dwc_otg_adp_sense_timer_start(core_if);
-+
-+ /* Clear interrupt */
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ adpctl.b.adp_sns_int = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function handles ADP Probe Interrupts
-+ */
-+static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
-+ uint32_t val)
-+{
-+ adpctl_data_t adpctl = {.d32 = 0 };
-+ adpctl.d32 = val;
-+ set_timer_value(core_if, adpctl.b.rtim);
-+
-+ /* Clear interrupt */
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ adpctl.b.adp_tmout_int = 1;
-+ dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+
-+ return 0;
-+}
-+
-+/**
-+ * ADP Interrupt handler.
-+ *
-+ */
-+int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
-+{
-+ int retval = 0;
-+ adpctl_data_t adpctl = {.d32 = 0};
-+
-+ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
-+ DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
-+
-+ if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
-+ DWC_PRINTF("ADP Sense interrupt\n");
-+ retval |= dwc_otg_adp_handle_sns_intr(core_if);
-+ }
-+ if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
-+ DWC_PRINTF("ADP timeout interrupt\n");
-+ retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
-+ }
-+ if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
-+ DWC_PRINTF("ADP Probe interrupt\n");
-+ adpctl.b.adp_prb_int = 1;
-+ retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
-+ }
-+
-+// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
-+ //dwc_otg_adp_write_reg(core_if, adpctl.d32);
-+ DWC_PRINTF("RETURN FROM ADP ISR\n");
-+
-+ return retval;
-+}
-+
-+/**
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
-+{
-+
-+#ifndef DWC_HOST_ONLY
-+ hprt0_data_t hprt0;
-+ gpwrdn_data_t gpwrdn;
-+ DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
-+
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ /* check which value is for device mode and which for Host mode */
-+ if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
-+ DWC_PRINTF("SRP: Host mode\n");
-+
-+ if (core_if->adp_enable) {
-+ dwc_otg_adp_probe_stop(core_if);
-+
-+ /* Power on the core */
-+ if (core_if->power_down == 2) {
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ }
-+
-+ core_if->op_state = A_HOST;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+ }
-+
-+ /* Turn on the port power bit. */
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtpwr = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ /* Start the Connection timer. So a message can be displayed
-+ * if connect does not occur within 10 seconds. */
-+ cil_hcd_session_start(core_if);
-+ } else {
-+ DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
-+ if (core_if->adp_enable) {
-+ dwc_otg_adp_probe_stop(core_if);
-+
-+ /* Power on the core */
-+ if (core_if->power_down == 2) {
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ }
-+
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 0;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
-+ gpwrdn.d32);
-+
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ }
-+ }
-+#endif
-+ return 1;
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_adp.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_adp.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_adp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_adp.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,80 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
-+ * $Revision: #7 $
-+ * $Date: 2011/10/24 $
-+ * $Change: 1871159 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#ifndef __DWC_OTG_ADP_H__
-+#define __DWC_OTG_ADP_H__
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the Attach Detect Protocol interfaces and defines
-+ * (functions) and structures for Linux.
-+ *
-+ */
-+
-+#define DWC_OTG_ADP_UNATTACHED 0
-+#define DWC_OTG_ADP_ATTACHED 1
-+#define DWC_OTG_ADP_UNKOWN 2
-+
-+typedef struct dwc_otg_adp {
-+ uint32_t adp_started;
-+ uint32_t initial_probe;
-+ int32_t probe_timer_values[2];
-+ uint32_t probe_enabled;
-+ uint32_t sense_enabled;
-+ dwc_timer_t *sense_timer;
-+ uint32_t sense_timer_started;
-+ dwc_timer_t *vbuson_timer;
-+ uint32_t vbuson_timer_started;
-+ uint32_t attached;
-+ uint32_t probe_counter;
-+ uint32_t gpwrdn;
-+} dwc_otg_adp_t;
-+
-+/**
-+ * Attach Detect Protocol functions
-+ */
-+
-+extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
-+extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
-+extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
-+extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
-+extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
-+extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
-+extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
-+extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
-+extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
-+
-+#endif //__DWC_OTG_ADP_H__
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_attr.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_attr.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_attr.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_attr.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1210 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
-+ * $Revision: #44 $
-+ * $Date: 2010/11/29 $
-+ * $Change: 1636033 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+/** @file
-+ *
-+ * The diagnostic interface will provide access to the controller for
-+ * bringing up the hardware and testing. The Linux driver attributes
-+ * feature will be used to provide the Linux Diagnostic
-+ * Interface. These attributes are accessed through sysfs.
-+ */
-+
-+/** @page "Linux Module Attributes"
-+ *
-+ * The Linux module attributes feature is used to provide the Linux
-+ * Diagnostic Interface. These attributes are accessed through sysfs.
-+ * The diagnostic interface will provide access to the controller for
-+ * bringing up the hardware and testing.
-+
-+ The following table shows the attributes.
-+ <table>
-+ <tr>
-+ <td><b> Name</b></td>
-+ <td><b> Description</b></td>
-+ <td><b> Access</b></td>
-+ </tr>
-+
-+ <tr>
-+ <td> mode </td>
-+ <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hnpcapable </td>
-+ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
-+ Read returns the current value.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> srpcapable </td>
-+ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
-+ Read returns the current value.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hsic_connect </td>
-+ <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
-+ Read returns the current value.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> inv_sel_hsic </td>
-+ <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
-+ Read returns the current value.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hnp </td>
-+ <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> srp </td>
-+ <td> Initiates the Session Request Protocol. Read returns the status.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> buspower </td>
-+ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> bussuspend </td>
-+ <td> Suspends the USB bus.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> busconnected </td>
-+ <td> Gets the connection status of the bus</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> gotgctl </td>
-+ <td> Gets or sets the Core Control Status Register.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> gusbcfg </td>
-+ <td> Gets or sets the Core USB Configuration Register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> grxfsiz </td>
-+ <td> Gets or sets the Receive FIFO Size Register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> gnptxfsiz </td>
-+ <td> Gets or sets the non-periodic Transmit Size Register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> gpvndctl </td>
-+ <td> Gets or sets the PHY Vendor Control Register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> ggpio </td>
-+ <td> Gets the value in the lower 16-bits of the General Purpose IO Register
-+ or sets the upper 16 bits.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> guid </td>
-+ <td> Gets or sets the value of the User ID Register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> gsnpsid </td>
-+ <td> Gets the value of the Synopsys ID Regester</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> devspeed </td>
-+ <td> Gets or sets the device speed setting in the DCFG register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> enumspeed </td>
-+ <td> Gets the device enumeration Speed.</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hptxfsiz </td>
-+ <td> Gets the value of the Host Periodic Transmit FIFO</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hprt0 </td>
-+ <td> Gets or sets the value in the Host Port Control and Status Register</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> regoffset </td>
-+ <td> Sets the register offset for the next Register Access</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> regvalue </td>
-+ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> remote_wakeup </td>
-+ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
-+ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
-+ Wakeup signalling bit in the Device Control Register is set for 1
-+ milli-second.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> rem_wakeup_pwrdn </td>
-+ <td> On read, shows the status core - hibernated or not. On write, initiates
-+ a remote wakeup of the device from Hibernation. </td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> mode_ch_tim_en </td>
-+ <td> This bit is used to enable or disable the host core to wait for 200 PHY
-+ clock cycles at the end of Resume to change the opmode signal to the PHY to 00
-+ after Suspend or LPM. </td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> fr_interval </td>
-+ <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
-+ reload HFIR register during runtime. The application can write a value to this
-+ register only after the Port Enable bit of the Host Port Control and Status
-+ register (HPRT.PrtEnaPort) has been set </td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> disconnect_us </td>
-+ <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
-+ which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
-+ <td> Read/Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> regdump </td>
-+ <td> Dumps the contents of core registers.</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> spramdump </td>
-+ <td> Dumps the contents of core registers.</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hcddump </td>
-+ <td> Dumps the current HCD state.</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> hcd_frrem </td>
-+ <td> Shows the average value of the Frame Remaining
-+ field in the Host Frame Number/Frame Remaining register when an SOF interrupt
-+ occurs. This can be used to determine the average interrupt latency. Also
-+ shows the average Frame Remaining value for start_transfer and the "a" and
-+ "b" sample points. The "a" and "b" sample points may be used during debugging
-+ bto determine how long it takes to execute a section of the HCD code.</td>
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> rd_reg_test </td>
-+ <td> Displays the time required to read the GNPTXFSIZ register many times
-+ (the output shows the number of times the register is read).
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> wr_reg_test </td>
-+ <td> Displays the time required to write the GNPTXFSIZ register many times
-+ (the output shows the number of times the register is written).
-+ <td> Read</td>
-+ </tr>
-+
-+ <tr>
-+ <td> lpm_response </td>
-+ <td> Gets or sets lpm_response mode. Applicable only in device mode.
-+ <td> Write</td>
-+ </tr>
-+
-+ <tr>
-+ <td> sleep_status </td>
-+ <td> Shows sleep status of device.
-+ <td> Read</td>
-+ </tr>
-+
-+ </table>
-+
-+ Example usage:
-+ To get the current mode:
-+ cat /sys/devices/lm0/mode
-+
-+ To power down the USB:
-+ echo 0 > /sys/devices/lm0/buspower
-+ */
-+
-+#include "dwc_otg_os_dep.h"
-+#include "dwc_os.h"
-+#include "dwc_otg_driver.h"
-+#include "dwc_otg_attr.h"
-+#include "dwc_otg_core_if.h"
-+#include "dwc_otg_pcd_if.h"
-+#include "dwc_otg_hcd_if.h"
-+
-+/*
-+ * MACROs for defining sysfs attribute
-+ */
-+#ifdef LM_INTERFACE
-+
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
-+{ \
-+ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
-+ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
-+ uint32_t val; \
-+ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
-+ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
-+}
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
-+ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
-+ uint32_t set = simple_strtoul(buf, NULL, 16); \
-+ dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
-+ return count; \
-+}
-+
-+#elif defined(PCI_INTERFACE)
-+
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
-+{ \
-+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
-+ uint32_t val; \
-+ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
-+ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
-+}
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
-+ uint32_t set = simple_strtoul(buf, NULL, 16); \
-+ dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
-+ return count; \
-+}
-+
-+#elif defined(PLATFORM_INTERFACE)
-+
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
-+{ \
-+ struct platform_device *platform_dev = \
-+ container_of(_dev, struct platform_device, dev); \
-+ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
-+ uint32_t val; \
-+ DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
-+ __func__, _dev, platform_dev, otg_dev); \
-+ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
-+ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
-+}
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
-+ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
-+ uint32_t set = simple_strtoul(buf, NULL, 16); \
-+ dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
-+ return count; \
-+}
-+#endif
-+
-+/*
-+ * MACROs for defining sysfs attribute for 32-bit registers
-+ */
-+#ifdef LM_INTERFACE
-+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
-+{ \
-+ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
-+ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
-+ uint32_t val; \
-+ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
-+ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
-+}
-+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
-+ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
-+ uint32_t val = simple_strtoul(buf, NULL, 16); \
-+ dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
-+ return count; \
-+}
-+#elif defined(PCI_INTERFACE)
-+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
-+{ \
-+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
-+ uint32_t val; \
-+ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
-+ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
-+}
-+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
-+ uint32_t val = simple_strtoul(buf, NULL, 16); \
-+ dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
-+ return count; \
-+}
-+
-+#elif defined(PLATFORM_INTERFACE)
-+#include "dwc_otg_dbg.h"
-+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
-+{ \
-+ struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
-+ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
-+ uint32_t val; \
-+ DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
-+ __func__, _dev, platform_dev, otg_dev); \
-+ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
-+ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
-+}
-+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
-+static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
-+ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
-+ uint32_t val = simple_strtoul(buf, NULL, 16); \
-+ dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
-+ return count; \
-+}
-+
-+#endif
-+
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
-+DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
-+DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
-+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
-+
-+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
-+DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
-+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
-+
-+#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
-+DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
-+DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
-+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
-+
-+#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
-+DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
-+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
-+
-+/** @name Functions for Show/Store of Attributes */
-+/**@{*/
-+
-+/**
-+ * Helper function returning the otg_device structure of the given device
-+ */
-+static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
-+{
-+ dwc_otg_device_t *otg_dev;
-+ DWC_OTG_GETDRVDEV(otg_dev, _dev);
-+ return otg_dev;
-+}
-+
-+/**
-+ * Show the register offset of the Register Access.
-+ */
-+static ssize_t regoffset_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
-+ otg_dev->os_dep.reg_offset);
-+}
-+
-+/**
-+ * Set the register offset for the next Register Access Read/Write
-+ */
-+static ssize_t regoffset_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t offset = simple_strtoul(buf, NULL, 16);
-+#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
-+ if (offset < SZ_256K) {
-+#elif defined(PCI_INTERFACE)
-+ if (offset < 0x00040000) {
-+#endif
-+ otg_dev->os_dep.reg_offset = offset;
-+ } else {
-+ dev_err(_dev, "invalid offset\n");
-+ }
-+
-+ return count;
-+}
-+
-+DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
-+
-+/**
-+ * Show the value of the register at the offset in the reg_offset
-+ * attribute.
-+ */
-+static ssize_t regvalue_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t val;
-+ volatile uint32_t *addr;
-+
-+ if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
-+ /* Calculate the address */
-+ addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
-+ (uint8_t *) otg_dev->os_dep.base);
-+ val = DWC_READ_REG32(addr);
-+ return snprintf(buf,
-+ sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
-+ "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
-+ val);
-+ } else {
-+ dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
-+ return sprintf(buf, "invalid offset\n");
-+ }
-+}
-+
-+/**
-+ * Store the value in the register at the offset in the reg_offset
-+ * attribute.
-+ *
-+ */
-+static ssize_t regvalue_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ volatile uint32_t *addr;
-+ uint32_t val = simple_strtoul(buf, NULL, 16);
-+ //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
-+ if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
-+ /* Calculate the address */
-+ addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
-+ (uint8_t *) otg_dev->os_dep.base);
-+ DWC_WRITE_REG32(addr, val);
-+ } else {
-+ dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
-+ otg_dev->os_dep.reg_offset);
-+ }
-+ return count;
-+}
-+
-+DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
-+
-+/*
-+ * Attributes
-+ */
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
-+
-+//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
-+//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
-+
-+DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
-+ &(otg_dev->core_if->core_global_regs->gusbcfg),
-+ "GUSBCFG");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
-+ &(otg_dev->core_if->core_global_regs->grxfsiz),
-+ "GRXFSIZ");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
-+ &(otg_dev->core_if->core_global_regs->gnptxfsiz),
-+ "GNPTXFSIZ");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
-+ &(otg_dev->core_if->core_global_regs->gpvndctl),
-+ "GPVNDCTL");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
-+ &(otg_dev->core_if->core_global_regs->ggpio),
-+ "GGPIO");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
-+ "GUID");
-+DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
-+ &(otg_dev->core_if->core_global_regs->gsnpsid),
-+ "GSNPSID");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
-+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
-+
-+DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
-+ &(otg_dev->core_if->core_global_regs->hptxfsiz),
-+ "HPTXFSIZ");
-+DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
-+
-+/**
-+ * @todo Add code to initiate the HNP.
-+ */
-+/**
-+ * Show the HNP status bit
-+ */
-+static ssize_t hnp_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "HstNegScs = 0x%x\n",
-+ dwc_otg_get_hnpstatus(otg_dev->core_if));
-+}
-+
-+/**
-+ * Set the HNP Request bit
-+ */
-+static ssize_t hnp_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t in = simple_strtoul(buf, NULL, 16);
-+ dwc_otg_set_hnpreq(otg_dev->core_if, in);
-+ return count;
-+}
-+
-+DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
-+
-+/**
-+ * @todo Add code to initiate the SRP.
-+ */
-+/**
-+ * Show the SRP status bit
-+ */
-+static ssize_t srp_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "SesReqScs = 0x%x\n",
-+ dwc_otg_get_srpstatus(otg_dev->core_if));
-+#else
-+ return sprintf(buf, "Host Only Mode!\n");
-+#endif
-+}
-+
-+/**
-+ * Set the SRP Request bit
-+ */
-+static ssize_t srp_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ dwc_otg_pcd_initiate_srp(otg_dev->pcd);
-+#endif
-+ return count;
-+}
-+
-+DEVICE_ATTR(srp, 0644, srp_show, srp_store);
-+
-+/**
-+ * @todo Need to do more for power on/off?
-+ */
-+/**
-+ * Show the Bus Power status
-+ */
-+static ssize_t buspower_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "Bus Power = 0x%x\n",
-+ dwc_otg_get_prtpower(otg_dev->core_if));
-+}
-+
-+/**
-+ * Set the Bus Power status
-+ */
-+static ssize_t buspower_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t on = simple_strtoul(buf, NULL, 16);
-+ dwc_otg_set_prtpower(otg_dev->core_if, on);
-+ return count;
-+}
-+
-+DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
-+
-+/**
-+ * @todo Need to do more for suspend?
-+ */
-+/**
-+ * Show the Bus Suspend status
-+ */
-+static ssize_t bussuspend_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "Bus Suspend = 0x%x\n",
-+ dwc_otg_get_prtsuspend(otg_dev->core_if));
-+}
-+
-+/**
-+ * Set the Bus Suspend status
-+ */
-+static ssize_t bussuspend_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t in = simple_strtoul(buf, NULL, 16);
-+ dwc_otg_set_prtsuspend(otg_dev->core_if, in);
-+ return count;
-+}
-+
-+DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
-+
-+/**
-+ * Show the Mode Change Ready Timer status
-+ */
-+static ssize_t mode_ch_tim_en_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
-+ dwc_otg_get_mode_ch_tim(otg_dev->core_if));
-+}
-+
-+/**
-+ * Set the Mode Change Ready Timer status
-+ */
-+static ssize_t mode_ch_tim_en_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t in = simple_strtoul(buf, NULL, 16);
-+ dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
-+ return count;
-+}
-+
-+DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
-+
-+/**
-+ * Show the value of HFIR Frame Interval bitfield
-+ */
-+static ssize_t fr_interval_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "Frame Interval = 0x%x\n",
-+ dwc_otg_get_fr_interval(otg_dev->core_if));
-+}
-+
-+/**
-+ * Set the HFIR Frame Interval value
-+ */
-+static ssize_t fr_interval_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t in = simple_strtoul(buf, NULL, 10);
-+ dwc_otg_set_fr_interval(otg_dev->core_if, in);
-+ return count;
-+}
-+
-+DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
-+
-+/**
-+ * Show the status of Remote Wakeup.
-+ */
-+static ssize_t remote_wakeup_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+
-+ return sprintf(buf,
-+ "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
-+ dwc_otg_get_remotewakesig(otg_dev->core_if),
-+ dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
-+ dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
-+#else
-+ return sprintf(buf, "Host Only Mode!\n");
-+#endif /* DWC_HOST_ONLY */
-+}
-+
-+/**
-+ * Initiate a remote wakeup of the host. The Device control register
-+ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
-+ * flag is set.
-+ *
-+ */
-+static ssize_t remote_wakeup_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t val = simple_strtoul(buf, NULL, 16);
-+
-+ if (val & 1) {
-+ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
-+ } else {
-+ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
-+ }
-+#endif /* DWC_HOST_ONLY */
-+ return count;
-+}
-+
-+DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
-+ remote_wakeup_store);
-+
-+/**
-+ * Show the whether core is hibernated or not.
-+ */
-+static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+
-+ if (dwc_otg_get_core_state(otg_dev->core_if)) {
-+ DWC_PRINTF("Core is in hibernation\n");
-+ } else {
-+ DWC_PRINTF("Core is not in hibernation\n");
-+ }
-+#endif /* DWC_HOST_ONLY */
-+ return 0;
-+}
-+
-+extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
-+ int rem_wakeup, int reset);
-+
-+/**
-+ * Initiate a remote wakeup of the device to exit from hibernation.
-+ */
-+static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
-+#endif
-+ return count;
-+}
-+
-+DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
-+ rem_wakeup_pwrdn_store);
-+
-+static ssize_t disconnect_us(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+
-+#ifndef DWC_HOST_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t val = simple_strtoul(buf, NULL, 16);
-+ DWC_PRINTF("The Passed value is %04x\n", val);
-+
-+ dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
-+
-+#endif /* DWC_HOST_ONLY */
-+ return count;
-+}
-+
-+DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
-+
-+/**
-+ * Dump global registers and either host or device registers (depending on the
-+ * current mode of the core).
-+ */
-+static ssize_t regdump_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+
-+ dwc_otg_dump_global_registers(otg_dev->core_if);
-+ if (dwc_otg_is_host_mode(otg_dev->core_if)) {
-+ dwc_otg_dump_host_registers(otg_dev->core_if);
-+ } else {
-+ dwc_otg_dump_dev_registers(otg_dev->core_if);
-+
-+ }
-+ return sprintf(buf, "Register Dump\n");
-+}
-+
-+DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0);
-+
-+/**
-+ * Dump global registers and either host or device registers (depending on the
-+ * current mode of the core).
-+ */
-+static ssize_t spramdump_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+
-+ //dwc_otg_dump_spram(otg_dev->core_if);
-+
-+ return sprintf(buf, "SPRAM Dump\n");
-+}
-+
-+DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0);
-+
-+/**
-+ * Dump the current hcd state.
-+ */
-+static ssize_t hcddump_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+#ifndef DWC_DEVICE_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ dwc_otg_hcd_dump_state(otg_dev->hcd);
-+#endif /* DWC_DEVICE_ONLY */
-+ return sprintf(buf, "HCD Dump\n");
-+}
-+
-+DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0);
-+
-+/**
-+ * Dump the average frame remaining at SOF. This can be used to
-+ * determine average interrupt latency. Frame remaining is also shown for
-+ * start transfer and two additional sample points.
-+ */
-+static ssize_t hcd_frrem_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+#ifndef DWC_DEVICE_ONLY
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+
-+ dwc_otg_hcd_dump_frrem(otg_dev->hcd);
-+#endif /* DWC_DEVICE_ONLY */
-+ return sprintf(buf, "HCD Dump Frame Remaining\n");
-+}
-+
-+DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0);
-+
-+/**
-+ * Displays the time required to read the GNPTXFSIZ register many times (the
-+ * output shows the number of times the register is read).
-+ */
-+#define RW_REG_COUNT 10000000
-+#define MSEC_PER_JIFFIE 1000/HZ
-+static ssize_t rd_reg_test_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ int i;
-+ int time;
-+ int start_jiffies;
-+
-+ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
-+ HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
-+ start_jiffies = jiffies;
-+ for (i = 0; i < RW_REG_COUNT; i++) {
-+ dwc_otg_get_gnptxfsiz(otg_dev->core_if);
-+ }
-+ time = jiffies - start_jiffies;
-+ return sprintf(buf,
-+ "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
-+ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
-+}
-+
-+DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0);
-+
-+/**
-+ * Displays the time required to write the GNPTXFSIZ register many times (the
-+ * output shows the number of times the register is written).
-+ */
-+static ssize_t wr_reg_test_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t reg_val;
-+ int i;
-+ int time;
-+ int start_jiffies;
-+
-+ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
-+ HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
-+ reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
-+ start_jiffies = jiffies;
-+ for (i = 0; i < RW_REG_COUNT; i++) {
-+ dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
-+ }
-+ time = jiffies - start_jiffies;
-+ return sprintf(buf,
-+ "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
-+ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
-+}
-+
-+DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0);
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+
-+/**
-+* Show the lpm_response attribute.
-+*/
-+static ssize_t lpmresp_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+
-+ if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
-+ return sprintf(buf, "** LPM is DISABLED **\n");
-+
-+ if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
-+ return sprintf(buf, "** Current mode is not device mode\n");
-+ }
-+ return sprintf(buf, "lpm_response = %d\n",
-+ dwc_otg_get_lpmresponse(otg_dev->core_if));
-+}
-+
-+/**
-+* Store the lpm_response attribute.
-+*/
-+static ssize_t lpmresp_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ uint32_t val = simple_strtoul(buf, NULL, 16);
-+
-+ if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
-+ return 0;
-+ }
-+
-+ if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
-+ return 0;
-+ }
-+
-+ dwc_otg_set_lpmresponse(otg_dev->core_if, val);
-+ return count;
-+}
-+
-+DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
-+
-+/**
-+* Show the sleep_status attribute.
-+*/
-+static ssize_t sleepstatus_show(struct device *_dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ return sprintf(buf, "Sleep Status = %d\n",
-+ dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
-+}
-+
-+/**
-+ * Store the sleep_status attribure.
-+ */
-+static ssize_t sleepstatus_store(struct device *_dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-+ dwc_otg_core_if_t *core_if = otg_dev->core_if;
-+
-+ if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
-+ if (dwc_otg_is_host_mode(core_if)) {
-+
-+ DWC_PRINTF("Host initiated resume\n");
-+ dwc_otg_set_prtresume(otg_dev->core_if, 1);
-+ }
-+ }
-+
-+ return count;
-+}
-+
-+DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
-+ sleepstatus_store);
-+
-+#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
-+
-+/**@}*/
-+
-+/**
-+ * Create the device files
-+ */
-+void dwc_otg_attr_create(
-+#ifdef LM_INTERFACE
-+ struct lm_device *dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *dev
-+#endif
-+ )
-+{
-+ int error;
-+
-+ error = device_create_file(&dev->dev, &dev_attr_regoffset);
-+ error = device_create_file(&dev->dev, &dev_attr_regvalue);
-+ error = device_create_file(&dev->dev, &dev_attr_mode);
-+ error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
-+ error = device_create_file(&dev->dev, &dev_attr_srpcapable);
-+ error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
-+ error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
-+ error = device_create_file(&dev->dev, &dev_attr_hnp);
-+ error = device_create_file(&dev->dev, &dev_attr_srp);
-+ error = device_create_file(&dev->dev, &dev_attr_buspower);
-+ error = device_create_file(&dev->dev, &dev_attr_bussuspend);
-+ error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
-+ error = device_create_file(&dev->dev, &dev_attr_fr_interval);
-+ error = device_create_file(&dev->dev, &dev_attr_busconnected);
-+ error = device_create_file(&dev->dev, &dev_attr_gotgctl);
-+ error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
-+ error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
-+ error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
-+ error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
-+ error = device_create_file(&dev->dev, &dev_attr_ggpio);
-+ error = device_create_file(&dev->dev, &dev_attr_guid);
-+ error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
-+ error = device_create_file(&dev->dev, &dev_attr_devspeed);
-+ error = device_create_file(&dev->dev, &dev_attr_enumspeed);
-+ error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
-+ error = device_create_file(&dev->dev, &dev_attr_hprt0);
-+ error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
-+ error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
-+ error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
-+ error = device_create_file(&dev->dev, &dev_attr_regdump);
-+ error = device_create_file(&dev->dev, &dev_attr_spramdump);
-+ error = device_create_file(&dev->dev, &dev_attr_hcddump);
-+ error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
-+ error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
-+ error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ error = device_create_file(&dev->dev, &dev_attr_lpm_response);
-+ error = device_create_file(&dev->dev, &dev_attr_sleep_status);
-+#endif
-+}
-+
-+/**
-+ * Remove the device files
-+ */
-+void dwc_otg_attr_remove(
-+#ifdef LM_INTERFACE
-+ struct lm_device *dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *dev
-+#endif
-+ )
-+{
-+ device_remove_file(&dev->dev, &dev_attr_regoffset);
-+ device_remove_file(&dev->dev, &dev_attr_regvalue);
-+ device_remove_file(&dev->dev, &dev_attr_mode);
-+ device_remove_file(&dev->dev, &dev_attr_hnpcapable);
-+ device_remove_file(&dev->dev, &dev_attr_srpcapable);
-+ device_remove_file(&dev->dev, &dev_attr_hsic_connect);
-+ device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
-+ device_remove_file(&dev->dev, &dev_attr_hnp);
-+ device_remove_file(&dev->dev, &dev_attr_srp);
-+ device_remove_file(&dev->dev, &dev_attr_buspower);
-+ device_remove_file(&dev->dev, &dev_attr_bussuspend);
-+ device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
-+ device_remove_file(&dev->dev, &dev_attr_fr_interval);
-+ device_remove_file(&dev->dev, &dev_attr_busconnected);
-+ device_remove_file(&dev->dev, &dev_attr_gotgctl);
-+ device_remove_file(&dev->dev, &dev_attr_gusbcfg);
-+ device_remove_file(&dev->dev, &dev_attr_grxfsiz);
-+ device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
-+ device_remove_file(&dev->dev, &dev_attr_gpvndctl);
-+ device_remove_file(&dev->dev, &dev_attr_ggpio);
-+ device_remove_file(&dev->dev, &dev_attr_guid);
-+ device_remove_file(&dev->dev, &dev_attr_gsnpsid);
-+ device_remove_file(&dev->dev, &dev_attr_devspeed);
-+ device_remove_file(&dev->dev, &dev_attr_enumspeed);
-+ device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
-+ device_remove_file(&dev->dev, &dev_attr_hprt0);
-+ device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
-+ device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
-+ device_remove_file(&dev->dev, &dev_attr_disconnect_us);
-+ device_remove_file(&dev->dev, &dev_attr_regdump);
-+ device_remove_file(&dev->dev, &dev_attr_spramdump);
-+ device_remove_file(&dev->dev, &dev_attr_hcddump);
-+ device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
-+ device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
-+ device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ device_remove_file(&dev->dev, &dev_attr_lpm_response);
-+ device_remove_file(&dev->dev, &dev_attr_sleep_status);
-+#endif
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_attr.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_attr.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_attr.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_attr.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,89 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
-+ * $Revision: #13 $
-+ * $Date: 2010/06/21 $
-+ * $Change: 1532021 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#if !defined(__DWC_OTG_ATTR_H__)
-+#define __DWC_OTG_ATTR_H__
-+
-+/** @file
-+ * This file contains the interface to the Linux device attributes.
-+ */
-+extern struct device_attribute dev_attr_regoffset;
-+extern struct device_attribute dev_attr_regvalue;
-+
-+extern struct device_attribute dev_attr_mode;
-+extern struct device_attribute dev_attr_hnpcapable;
-+extern struct device_attribute dev_attr_srpcapable;
-+extern struct device_attribute dev_attr_hnp;
-+extern struct device_attribute dev_attr_srp;
-+extern struct device_attribute dev_attr_buspower;
-+extern struct device_attribute dev_attr_bussuspend;
-+extern struct device_attribute dev_attr_mode_ch_tim_en;
-+extern struct device_attribute dev_attr_fr_interval;
-+extern struct device_attribute dev_attr_busconnected;
-+extern struct device_attribute dev_attr_gotgctl;
-+extern struct device_attribute dev_attr_gusbcfg;
-+extern struct device_attribute dev_attr_grxfsiz;
-+extern struct device_attribute dev_attr_gnptxfsiz;
-+extern struct device_attribute dev_attr_gpvndctl;
-+extern struct device_attribute dev_attr_ggpio;
-+extern struct device_attribute dev_attr_guid;
-+extern struct device_attribute dev_attr_gsnpsid;
-+extern struct device_attribute dev_attr_devspeed;
-+extern struct device_attribute dev_attr_enumspeed;
-+extern struct device_attribute dev_attr_hptxfsiz;
-+extern struct device_attribute dev_attr_hprt0;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+extern struct device_attribute dev_attr_lpm_response;
-+extern struct device_attribute devi_attr_sleep_status;
-+#endif
-+
-+void dwc_otg_attr_create(
-+#ifdef LM_INTERFACE
-+ struct lm_device *dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *dev
-+#endif
-+ );
-+
-+void dwc_otg_attr_remove(
-+#ifdef LM_INTERFACE
-+ struct lm_device *dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *dev
-+#endif
-+ );
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cfi.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cfi.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cfi.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1876 @@
-+/* ==========================================================================
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+/** @file
-+ *
-+ * This file contains the most of the CFI(Core Feature Interface)
-+ * implementation for the OTG.
-+ */
-+
-+#ifdef DWC_UTE_CFI
-+
-+#include "dwc_otg_pcd.h"
-+#include "dwc_otg_cfi.h"
-+
-+/** This definition should actually migrate to the Portability Library */
-+#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
-+
-+extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
-+
-+static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
-+static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
-+ struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *ctrl_req);
-+static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
-+static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req);
-+static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req);
-+static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req);
-+static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req);
-+static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
-+
-+static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
-+static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
-+static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
-+
-+static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
-+
-+/** This is the header of the all features descriptor */
-+static cfi_all_features_header_t all_props_desc_header = {
-+ .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
-+ .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
-+ .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
-+};
-+
-+/** This is an array of statically allocated feature descriptors */
-+static cfi_feature_desc_header_t prop_descs[] = {
-+
-+ /* FT_ID_DMA_MODE */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
-+ },
-+
-+ /* FT_ID_DMA_BUFFER_SETUP */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
-+ },
-+
-+ /* FT_ID_DMA_BUFF_ALIGN */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
-+ },
-+
-+ /* FT_ID_DMA_CONCAT_SETUP */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
-+ },
-+
-+ /* FT_ID_DMA_CIRCULAR */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
-+ },
-+
-+ /* FT_ID_THRESHOLD_SETUP */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
-+ },
-+
-+ /* FT_ID_DFIFO_DEPTH */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
-+ .bmAttributes = CFI_FEATURE_ATTR_RO,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
-+ },
-+
-+ /* FT_ID_TX_FIFO_DEPTH */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
-+ },
-+
-+ /* FT_ID_RX_FIFO_DEPTH */
-+ {
-+ .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
-+ .bmAttributes = CFI_FEATURE_ATTR_RW,
-+ .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
-+ }
-+};
-+
-+/** The table of feature names */
-+cfi_string_t prop_name_table[] = {
-+ {FT_ID_DMA_MODE, "dma_mode"},
-+ {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
-+ {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
-+ {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
-+ {FT_ID_DMA_CIRCULAR, "buffer_circular"},
-+ {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
-+ {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
-+ {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
-+ {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
-+ {}
-+};
-+
-+/************************************************************************/
-+
-+/**
-+ * Returns the name of the feature by its ID
-+ * or NULL if no featute ID matches.
-+ *
-+ */
-+const uint8_t *get_prop_name(uint16_t prop_id, int *len)
-+{
-+ cfi_string_t *pstr;
-+ *len = 0;
-+
-+ for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
-+ if (pstr->id == prop_id) {
-+ *len = DWC_STRLEN(pstr->s);
-+ return pstr->s;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+/**
-+ * This function handles all CFI specific control requests.
-+ *
-+ * Return a negative value to stall the DCE.
-+ */
-+int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
-+{
-+ int retval = 0;
-+ dwc_otg_pcd_ep_t *ep = NULL;
-+ cfiobject_t *cfi = pcd->cfi;
-+ struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
-+ uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
-+ uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
-+ uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
-+ uint32_t regaddr = 0;
-+ uint32_t regval = 0;
-+
-+ /* Save this Control Request in the CFI object.
-+ * The data field will be assigned in the data stage completion CB function.
-+ */
-+ cfi->ctrl_req = *ctrl;
-+ cfi->ctrl_req.data = NULL;
-+
-+ cfi->need_gadget_att = 0;
-+ cfi->need_status_in_complete = 0;
-+
-+ switch (ctrl->bRequest) {
-+ case VEN_CORE_GET_FEATURES:
-+ retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
-+ if (retval >= 0) {
-+ //dump_msg(cfi->buf_in.buf, retval);
-+ ep = &pcd->ep0;
-+
-+ retval = min((uint16_t) retval, wLen);
-+ /* Transfer this buffer to the host through the EP0-IN EP */
-+ ep->dwc_ep.dma_addr = cfi->buf_in.addr;
-+ ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
-+ ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
-+ ep->dwc_ep.xfer_len = retval;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
-+
-+ pcd->ep0_pending = 1;
-+ dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
-+ }
-+ retval = 0;
-+ break;
-+
-+ case VEN_CORE_GET_FEATURE:
-+ CFI_INFO("VEN_CORE_GET_FEATURE\n");
-+ retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
-+ pcd, ctrl);
-+ if (retval >= 0) {
-+ ep = &pcd->ep0;
-+
-+ retval = min((uint16_t) retval, wLen);
-+ /* Transfer this buffer to the host through the EP0-IN EP */
-+ ep->dwc_ep.dma_addr = cfi->buf_in.addr;
-+ ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
-+ ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
-+ ep->dwc_ep.xfer_len = retval;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
-+
-+ pcd->ep0_pending = 1;
-+ dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
-+ }
-+ CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
-+ dump_msg(cfi->buf_in.buf, retval);
-+ break;
-+
-+ case VEN_CORE_SET_FEATURE:
-+ CFI_INFO("VEN_CORE_SET_FEATURE\n");
-+ /* Set up an XFER to get the data stage of the control request,
-+ * which is the new value of the feature to be modified.
-+ */
-+ ep = &pcd->ep0;
-+ ep->dwc_ep.is_in = 0;
-+ ep->dwc_ep.dma_addr = cfi->buf_out.addr;
-+ ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
-+ ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
-+ ep->dwc_ep.xfer_len = wLen;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
-+
-+ pcd->ep0_pending = 1;
-+ /* Read the control write's data stage */
-+ dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
-+ retval = 0;
-+ break;
-+
-+ case VEN_CORE_RESET_FEATURES:
-+ CFI_INFO("VEN_CORE_RESET_FEATURES\n");
-+ cfi->need_gadget_att = 1;
-+ cfi->need_status_in_complete = 1;
-+ retval = cfi_preproc_reset(pcd, ctrl);
-+ CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
-+ break;
-+
-+ case VEN_CORE_ACTIVATE_FEATURES:
-+ CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
-+ break;
-+
-+ case VEN_CORE_READ_REGISTER:
-+ CFI_INFO("VEN_CORE_READ_REGISTER\n");
-+ /* wValue optionally contains the HI WORD of the register offset and
-+ * wIndex contains the LOW WORD of the register offset
-+ */
-+ if (wValue == 0) {
-+ /* @TODO - MAS - fix the access to the base field */
-+ regaddr = 0;
-+ //regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
-+ //GET_CORE_IF(pcd)->co
-+ regaddr |= wIndex;
-+ } else {
-+ regaddr = (wValue << 16) | wIndex;
-+ }
-+
-+ /* Read a 32-bit value of the memory at the regaddr */
-+ regval = DWC_READ_REG32((uint32_t *) regaddr);
-+
-+ ep = &pcd->ep0;
-+ dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
-+ ep->dwc_ep.is_in = 1;
-+ ep->dwc_ep.dma_addr = cfi->buf_in.addr;
-+ ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
-+ ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
-+ ep->dwc_ep.xfer_len = wLen;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
-+
-+ pcd->ep0_pending = 1;
-+ dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
-+ cfi->need_gadget_att = 0;
-+ retval = 0;
-+ break;
-+
-+ case VEN_CORE_WRITE_REGISTER:
-+ CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
-+ /* Set up an XFER to get the data stage of the control request,
-+ * which is the new value of the register to be modified.
-+ */
-+ ep = &pcd->ep0;
-+ ep->dwc_ep.is_in = 0;
-+ ep->dwc_ep.dma_addr = cfi->buf_out.addr;
-+ ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
-+ ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
-+ ep->dwc_ep.xfer_len = wLen;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
-+
-+ pcd->ep0_pending = 1;
-+ /* Read the control write's data stage */
-+ dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
-+ retval = 0;
-+ break;
-+
-+ default:
-+ retval = -DWC_E_NOT_SUPPORTED;
-+ break;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function prepares the core features descriptors and copies its
-+ * raw representation into the buffer <buf>.
-+ *
-+ * The buffer structure is as follows:
-+ * all_features_header (8 bytes)
-+ * features_#1 (8 bytes + feature name string length)
-+ * features_#2 (8 bytes + feature name string length)
-+ * .....
-+ * features_#n - where n=the total count of feature descriptors
-+ */
-+static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
-+{
-+ cfi_feature_desc_header_t *prop_hdr = prop_descs;
-+ cfi_feature_desc_header_t *prop;
-+ cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
-+ cfi_all_features_header_t *tmp;
-+ uint8_t *tmpbuf = buf;
-+ const uint8_t *pname = NULL;
-+ int i, j, namelen = 0, totlen;
-+
-+ /* Prepare and copy the core features into the buffer */
-+ CFI_INFO("%s:\n", __func__);
-+
-+ tmp = (cfi_all_features_header_t *) tmpbuf;
-+ *tmp = *all_props_hdr;
-+ tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
-+
-+ j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
-+ for (i = 0; i < j; i++, prop_hdr++) {
-+ pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
-+ prop = (cfi_feature_desc_header_t *) tmpbuf;
-+ *prop = *prop_hdr;
-+
-+ prop->bNameLen = namelen;
-+ prop->wLength =
-+ DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
-+ namelen);
-+
-+ tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
-+ dwc_memcpy(tmpbuf, pname, namelen);
-+ tmpbuf += namelen;
-+ }
-+
-+ totlen = tmpbuf - buf;
-+
-+ if (totlen > 0) {
-+ tmp = (cfi_all_features_header_t *) buf;
-+ tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
-+ }
-+
-+ return totlen;
-+}
-+
-+/**
-+ * This function releases all the dynamic memory in the CFI object.
-+ */
-+static void cfi_release(cfiobject_t * cfiobj)
-+{
-+ cfi_ep_t *cfiep;
-+ dwc_list_link_t *tmp;
-+
-+ CFI_INFO("%s\n", __func__);
-+
-+ if (cfiobj->buf_in.buf) {
-+ DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
-+ cfiobj->buf_in.addr);
-+ cfiobj->buf_in.buf = NULL;
-+ }
-+
-+ if (cfiobj->buf_out.buf) {
-+ DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
-+ cfiobj->buf_out.addr);
-+ cfiobj->buf_out.buf = NULL;
-+ }
-+
-+ /* Free the Buffer Setup values for each EP */
-+ //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
-+ DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
-+ cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+ cfi_free_ep_bs_dyn_data(cfiep);
-+ }
-+}
-+
-+/**
-+ * This function frees the dynamically allocated EP buffer setup data.
-+ */
-+static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
-+{
-+ if (cfiep->bm_sg) {
-+ DWC_FREE(cfiep->bm_sg);
-+ cfiep->bm_sg = NULL;
-+ }
-+
-+ if (cfiep->bm_align) {
-+ DWC_FREE(cfiep->bm_align);
-+ cfiep->bm_align = NULL;
-+ }
-+
-+ if (cfiep->bm_concat) {
-+ if (NULL != cfiep->bm_concat->wTxBytes) {
-+ DWC_FREE(cfiep->bm_concat->wTxBytes);
-+ cfiep->bm_concat->wTxBytes = NULL;
-+ }
-+ DWC_FREE(cfiep->bm_concat);
-+ cfiep->bm_concat = NULL;
-+ }
-+}
-+
-+/**
-+ * This function initializes the default values of the features
-+ * for a specific endpoint and should be called only once when
-+ * the EP is enabled first time.
-+ */
-+static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
-+{
-+ int retval = 0;
-+
-+ cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
-+ if (NULL == cfiep->bm_sg) {
-+ CFI_INFO("Failed to allocate memory for SG feature value\n");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
-+
-+ /* For the Concatenation feature's default value we do not allocate
-+ * memory for the wTxBytes field - it will be done in the set_feature_value
-+ * request handler.
-+ */
-+ cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
-+ if (NULL == cfiep->bm_concat) {
-+ CFI_INFO
-+ ("Failed to allocate memory for CONCATENATION feature value\n");
-+ DWC_FREE(cfiep->bm_sg);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
-+
-+ cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
-+ if (NULL == cfiep->bm_align) {
-+ CFI_INFO
-+ ("Failed to allocate memory for Alignment feature value\n");
-+ DWC_FREE(cfiep->bm_sg);
-+ DWC_FREE(cfiep->bm_concat);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
-+
-+ return retval;
-+}
-+
-+/**
-+ * The callback function that notifies the CFI on the activation of
-+ * an endpoint in the PCD. The following steps are done in this function:
-+ *
-+ * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
-+ * active endpoint)
-+ * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
-+ * Set the Buffer Mode to standard
-+ * Initialize the default values for all EP modes (SG, Circular, Concat, Align)
-+ * Add the cfi_ep_t object to the list of active endpoints in the CFI object
-+ */
-+static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
-+ struct dwc_otg_pcd_ep *ep)
-+{
-+ cfi_ep_t *cfiep;
-+ int retval = -DWC_E_NOT_SUPPORTED;
-+
-+ CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
-+ "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
-+ /* MAS - Check whether this endpoint already is in the list */
-+ cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
-+
-+ if (NULL == cfiep) {
-+ /* Allocate a cfi_ep_t object */
-+ cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
-+ if (NULL == cfiep) {
-+ CFI_INFO
-+ ("Unable to allocate memory for <cfiep> in function %s\n",
-+ __func__);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
-+
-+ /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
-+ cfiep->ep = ep;
-+
-+ /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
-+ ep->dwc_ep.descs =
-+ DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
-+ sizeof(dwc_otg_dma_desc_t),
-+ &ep->dwc_ep.descs_dma_addr);
-+
-+ if (NULL == ep->dwc_ep.descs) {
-+ DWC_FREE(cfiep);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ DWC_LIST_INIT(&cfiep->lh);
-+
-+ /* Set the buffer mode to BM_STANDARD. It will be modified
-+ * when building descriptors for a specific buffer mode */
-+ ep->dwc_ep.buff_mode = BM_STANDARD;
-+
-+ /* Create and initialize the default values for this EP's Buffer modes */
-+ if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
-+ return retval;
-+
-+ /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
-+ DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
-+ retval = 0;
-+ } else { /* The sought EP already is in the list */
-+ CFI_INFO("%s: The sought EP already is in the list\n",
-+ __func__);
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function is called when the data stage of a 3-stage Control Write request
-+ * is complete.
-+ *
-+ */
-+static int cfi_ctrl_write_complete(struct cfiobject *cfi,
-+ struct dwc_otg_pcd *pcd)
-+{
-+ uint32_t addr, reg_value;
-+ uint16_t wIndex, wValue;
-+ uint8_t bRequest;
-+ uint8_t *buf = cfi->buf_out.buf;
-+ //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
-+ struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
-+ int retval = -DWC_E_NOT_SUPPORTED;
-+
-+ CFI_INFO("%s\n", __func__);
-+
-+ bRequest = ctrl_req->bRequest;
-+ wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
-+ wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
-+
-+ /*
-+ * Save the pointer to the data stage in the ctrl_req's <data> field.
-+ * The request should be already saved in the command stage by now.
-+ */
-+ ctrl_req->data = cfi->buf_out.buf;
-+ cfi->need_status_in_complete = 0;
-+ cfi->need_gadget_att = 0;
-+
-+ switch (bRequest) {
-+ case VEN_CORE_WRITE_REGISTER:
-+ /* The buffer contains raw data of the new value for the register */
-+ reg_value = *((uint32_t *) buf);
-+ if (wValue == 0) {
-+ addr = 0;
-+ //addr = (uint32_t) pcd->otg_dev->os_dep.base;
-+ addr += wIndex;
-+ } else {
-+ addr = (wValue << 16) | wIndex;
-+ }
-+
-+ //writel(reg_value, addr);
-+
-+ retval = 0;
-+ cfi->need_status_in_complete = 1;
-+ break;
-+
-+ case VEN_CORE_SET_FEATURE:
-+ /* The buffer contains raw data of the new value of the feature */
-+ retval = cfi_set_feature_value(pcd);
-+ if (retval < 0)
-+ return retval;
-+
-+ cfi->need_status_in_complete = 1;
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function builds the DMA descriptors for the SG buffer mode.
-+ */
-+static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
-+ dwc_otg_pcd_request_t * req)
-+{
-+ struct dwc_otg_pcd_ep *ep = cfiep->ep;
-+ ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
-+ struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
-+ struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
-+ dma_addr_t buff_addr = req->dma;
-+ int i;
-+ uint32_t txsize, off;
-+
-+ txsize = sgval->wSize;
-+ off = sgval->bOffset;
-+
-+// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
-+// __func__, cfiep->ep->ep.name, txsize, off);
-+
-+ for (i = 0; i < sgval->bCount; i++) {
-+ desc->status.b.bs = BS_HOST_BUSY;
-+ desc->buf = buff_addr;
-+ desc->status.b.l = 0;
-+ desc->status.b.ioc = 0;
-+ desc->status.b.sp = 0;
-+ desc->status.b.bytes = txsize;
-+ desc->status.b.bs = BS_HOST_READY;
-+
-+ /* Set the next address of the buffer */
-+ buff_addr += txsize + off;
-+ desc_last = desc;
-+ desc++;
-+ }
-+
-+ /* Set the last, ioc and sp bits on the Last DMA Descriptor */
-+ desc_last->status.b.l = 1;
-+ desc_last->status.b.ioc = 1;
-+ desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
-+ /* Save the last DMA descriptor pointer */
-+ cfiep->dma_desc_last = desc_last;
-+ cfiep->desc_count = sgval->bCount;
-+}
-+
-+/**
-+ * This function builds the DMA descriptors for the Concatenation buffer mode.
-+ */
-+static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
-+ dwc_otg_pcd_request_t * req)
-+{
-+ struct dwc_otg_pcd_ep *ep = cfiep->ep;
-+ ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
-+ struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
-+ struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
-+ dma_addr_t buff_addr = req->dma;
-+ int i;
-+ uint16_t *txsize;
-+
-+ txsize = concatval->wTxBytes;
-+
-+ for (i = 0; i < concatval->hdr.bDescCount; i++) {
-+ desc->buf = buff_addr;
-+ desc->status.b.bs = BS_HOST_BUSY;
-+ desc->status.b.l = 0;
-+ desc->status.b.ioc = 0;
-+ desc->status.b.sp = 0;
-+ desc->status.b.bytes = *txsize;
-+ desc->status.b.bs = BS_HOST_READY;
-+
-+ txsize++;
-+ /* Set the next address of the buffer */
-+ buff_addr += UGETW(ep->desc->wMaxPacketSize);
-+ desc_last = desc;
-+ desc++;
-+ }
-+
-+ /* Set the last, ioc and sp bits on the Last DMA Descriptor */
-+ desc_last->status.b.l = 1;
-+ desc_last->status.b.ioc = 1;
-+ desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
-+ cfiep->dma_desc_last = desc_last;
-+ cfiep->desc_count = concatval->hdr.bDescCount;
-+}
-+
-+/**
-+ * This function builds the DMA descriptors for the Circular buffer mode
-+ */
-+static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
-+ dwc_otg_pcd_request_t * req)
-+{
-+ /* @todo: MAS - add implementation when this feature needs to be tested */
-+}
-+
-+/**
-+ * This function builds the DMA descriptors for the Alignment buffer mode
-+ */
-+static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
-+ dwc_otg_pcd_request_t * req)
-+{
-+ struct dwc_otg_pcd_ep *ep = cfiep->ep;
-+ ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
-+ struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
-+ dma_addr_t buff_addr = req->dma;
-+
-+ desc->status.b.bs = BS_HOST_BUSY;
-+ desc->status.b.l = 1;
-+ desc->status.b.ioc = 1;
-+ desc->status.b.sp = ep->dwc_ep.sent_zlp;
-+ desc->status.b.bytes = req->length;
-+ /* Adjust the buffer alignment */
-+ desc->buf = (buff_addr + alignval->bAlign);
-+ desc->status.b.bs = BS_HOST_READY;
-+ cfiep->dma_desc_last = desc;
-+ cfiep->desc_count = 1;
-+}
-+
-+/**
-+ * This function builds the DMA descriptors chain for different modes of the
-+ * buffer setup of an endpoint.
-+ */
-+static void cfi_build_descriptors(struct cfiobject *cfi,
-+ struct dwc_otg_pcd *pcd,
-+ struct dwc_otg_pcd_ep *ep,
-+ dwc_otg_pcd_request_t * req)
-+{
-+ cfi_ep_t *cfiep;
-+
-+ /* Get the cfiep by the dwc_otg_pcd_ep */
-+ cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
-+ if (NULL == cfiep) {
-+ CFI_INFO("%s: Unable to find a matching active endpoint\n",
-+ __func__);
-+ return;
-+ }
-+
-+ cfiep->xfer_len = req->length;
-+
-+ /* Iterate through all the DMA descriptors */
-+ switch (cfiep->ep->dwc_ep.buff_mode) {
-+ case BM_SG:
-+ cfi_build_sg_descs(cfi, cfiep, req);
-+ break;
-+
-+ case BM_CONCAT:
-+ cfi_build_concat_descs(cfi, cfiep, req);
-+ break;
-+
-+ case BM_CIRCULAR:
-+ cfi_build_circ_descs(cfi, cfiep, req);
-+ break;
-+
-+ case BM_ALIGN:
-+ cfi_build_align_descs(cfi, cfiep, req);
-+ break;
-+
-+ default:
-+ break;
-+ }
-+}
-+
-+/**
-+ * Allocate DMA buffer for different Buffer modes.
-+ */
-+static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
-+ struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
-+ unsigned size, gfp_t flags)
-+{
-+ return DWC_DMA_ALLOC(size, dma);
-+}
-+
-+/**
-+ * This function initializes the CFI object.
-+ */
-+int init_cfi(cfiobject_t * cfiobj)
-+{
-+ CFI_INFO("%s\n", __func__);
-+
-+ /* Allocate a buffer for IN XFERs */
-+ cfiobj->buf_in.buf =
-+ DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
-+ if (NULL == cfiobj->buf_in.buf) {
-+ CFI_INFO("Unable to allocate buffer for INs\n");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ /* Allocate a buffer for OUT XFERs */
-+ cfiobj->buf_out.buf =
-+ DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
-+ if (NULL == cfiobj->buf_out.buf) {
-+ CFI_INFO("Unable to allocate buffer for OUT\n");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ /* Initialize the callback function pointers */
-+ cfiobj->ops.release = cfi_release;
-+ cfiobj->ops.ep_enable = cfi_ep_enable;
-+ cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
-+ cfiobj->ops.build_descriptors = cfi_build_descriptors;
-+ cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
-+
-+ /* Initialize the list of active endpoints in the CFI object */
-+ DWC_LIST_INIT(&cfiobj->active_eps);
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function reads the required feature's current value into the buffer
-+ *
-+ * @retval: Returns negative as error, or the data length of the feature
-+ */
-+static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
-+ struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *ctrl_req)
-+{
-+ int retval = -DWC_E_NOT_SUPPORTED;
-+ struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
-+ uint16_t dfifo, rxfifo, txfifo;
-+
-+ switch (ctrl_req->wIndex) {
-+ /* Whether the DDMA is enabled or not */
-+ case FT_ID_DMA_MODE:
-+ *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
-+ retval = 1;
-+ break;
-+
-+ case FT_ID_DMA_BUFFER_SETUP:
-+ retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
-+ break;
-+
-+ case FT_ID_DMA_BUFF_ALIGN:
-+ retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
-+ break;
-+
-+ case FT_ID_DMA_CONCAT_SETUP:
-+ retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
-+ break;
-+
-+ case FT_ID_DMA_CIRCULAR:
-+ CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
-+ break;
-+
-+ case FT_ID_THRESHOLD_SETUP:
-+ CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
-+ break;
-+
-+ case FT_ID_DFIFO_DEPTH:
-+ dfifo = get_dfifo_size(coreif);
-+ *((uint16_t *) buf) = dfifo;
-+ retval = sizeof(uint16_t);
-+ break;
-+
-+ case FT_ID_TX_FIFO_DEPTH:
-+ retval = get_txfifo_size(pcd, ctrl_req->wValue);
-+ if (retval >= 0) {
-+ txfifo = retval;
-+ *((uint16_t *) buf) = txfifo;
-+ retval = sizeof(uint16_t);
-+ }
-+ break;
-+
-+ case FT_ID_RX_FIFO_DEPTH:
-+ retval = get_rxfifo_size(coreif, ctrl_req->wValue);
-+ if (retval >= 0) {
-+ rxfifo = retval;
-+ *((uint16_t *) buf) = rxfifo;
-+ retval = sizeof(uint16_t);
-+ }
-+ break;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function resets the SG for the specified EP to its default value
-+ */
-+static int cfi_reset_sg_val(cfi_ep_t * cfiep)
-+{
-+ dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
-+ return 0;
-+}
-+
-+/**
-+ * This function resets the Alignment for the specified EP to its default value
-+ */
-+static int cfi_reset_align_val(cfi_ep_t * cfiep)
-+{
-+ dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
-+ return 0;
-+}
-+
-+/**
-+ * This function resets the Concatenation for the specified EP to its default value
-+ * This function will also set the value of the wTxBytes field to NULL after
-+ * freeing the memory previously allocated for this field.
-+ */
-+static int cfi_reset_concat_val(cfi_ep_t * cfiep)
-+{
-+ /* First we need to free the wTxBytes field */
-+ if (cfiep->bm_concat->wTxBytes) {
-+ DWC_FREE(cfiep->bm_concat->wTxBytes);
-+ cfiep->bm_concat->wTxBytes = NULL;
-+ }
-+
-+ dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
-+ return 0;
-+}
-+
-+/**
-+ * This function resets all the buffer setups of the specified endpoint
-+ */
-+static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
-+{
-+ cfi_reset_sg_val(cfiep);
-+ cfi_reset_align_val(cfiep);
-+ cfi_reset_concat_val(cfiep);
-+ return 0;
-+}
-+
-+static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
-+ uint8_t rx_rst, uint8_t tx_rst)
-+{
-+ int retval = -DWC_E_INVALID;
-+ uint16_t tx_siz[15];
-+ uint16_t rx_siz = 0;
-+ dwc_otg_pcd_ep_t *ep = NULL;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
-+
-+ if (rx_rst) {
-+ rx_siz = params->dev_rx_fifo_size;
-+ params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
-+ }
-+
-+ if (tx_rst) {
-+ if (ep_addr == 0) {
-+ int i;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ tx_siz[i] =
-+ core_if->core_params->dev_tx_fifo_size[i];
-+ core_if->core_params->dev_tx_fifo_size[i] =
-+ core_if->init_txfsiz[i];
-+ }
-+ } else {
-+
-+ ep = get_ep_by_addr(pcd, ep_addr);
-+
-+ if (NULL == ep) {
-+ CFI_INFO
-+ ("%s: Unable to get the endpoint addr=0x%02x\n",
-+ __func__, ep_addr);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ tx_siz[0] =
-+ params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
-+ 1];
-+ params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
-+ GET_CORE_IF(pcd)->init_txfsiz[ep->
-+ dwc_ep.tx_fifo_num -
-+ 1];
-+ }
-+ }
-+
-+ if (resize_fifos(GET_CORE_IF(pcd))) {
-+ retval = 0;
-+ } else {
-+ CFI_INFO
-+ ("%s: Error resetting the feature Reset All(FIFO size)\n",
-+ __func__);
-+ if (rx_rst) {
-+ params->dev_rx_fifo_size = rx_siz;
-+ }
-+
-+ if (tx_rst) {
-+ if (ep_addr == 0) {
-+ int i;
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
-+ i++) {
-+ core_if->
-+ core_params->dev_tx_fifo_size[i] =
-+ tx_siz[i];
-+ }
-+ } else {
-+ params->dev_tx_fifo_size[ep->
-+ dwc_ep.tx_fifo_num -
-+ 1] = tx_siz[0];
-+ }
-+ }
-+ retval = -DWC_E_INVALID;
-+ }
-+ return retval;
-+}
-+
-+static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
-+{
-+ int retval = 0;
-+ cfi_ep_t *cfiep;
-+ cfiobject_t *cfi = pcd->cfi;
-+ dwc_list_link_t *tmp;
-+
-+ retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
-+ if (retval < 0) {
-+ return retval;
-+ }
-+
-+ /* If the EP address is known then reset the features for only that EP */
-+ if (addr) {
-+ cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == cfiep) {
-+ CFI_INFO("%s: Error getting the EP address 0x%02x\n",
-+ __func__, addr);
-+ return -DWC_E_INVALID;
-+ }
-+ retval = cfi_ep_reset_all_setup_vals(cfiep);
-+ cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
-+ }
-+ /* Otherwise (wValue == 0), reset all features of all EP's */
-+ else {
-+ /* Traverse all the active EP's and reset the feature(s) value(s) */
-+ //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
-+ DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
-+ cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+ retval = cfi_ep_reset_all_setup_vals(cfiep);
-+ cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
-+ if (retval < 0) {
-+ CFI_INFO
-+ ("%s: Error resetting the feature Reset All\n",
-+ __func__);
-+ return retval;
-+ }
-+ }
-+ }
-+ return retval;
-+}
-+
-+static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
-+ uint8_t addr)
-+{
-+ int retval = 0;
-+ cfi_ep_t *cfiep;
-+ cfiobject_t *cfi = pcd->cfi;
-+ dwc_list_link_t *tmp;
-+
-+ /* If the EP address is known then reset the features for only that EP */
-+ if (addr) {
-+ cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == cfiep) {
-+ CFI_INFO("%s: Error getting the EP address 0x%02x\n",
-+ __func__, addr);
-+ return -DWC_E_INVALID;
-+ }
-+ retval = cfi_reset_sg_val(cfiep);
-+ }
-+ /* Otherwise (wValue == 0), reset all features of all EP's */
-+ else {
-+ /* Traverse all the active EP's and reset the feature(s) value(s) */
-+ //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
-+ DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
-+ cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+ retval = cfi_reset_sg_val(cfiep);
-+ if (retval < 0) {
-+ CFI_INFO
-+ ("%s: Error resetting the feature Buffer Setup\n",
-+ __func__);
-+ return retval;
-+ }
-+ }
-+ }
-+ return retval;
-+}
-+
-+static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
-+{
-+ int retval = 0;
-+ cfi_ep_t *cfiep;
-+ cfiobject_t *cfi = pcd->cfi;
-+ dwc_list_link_t *tmp;
-+
-+ /* If the EP address is known then reset the features for only that EP */
-+ if (addr) {
-+ cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == cfiep) {
-+ CFI_INFO("%s: Error getting the EP address 0x%02x\n",
-+ __func__, addr);
-+ return -DWC_E_INVALID;
-+ }
-+ retval = cfi_reset_concat_val(cfiep);
-+ }
-+ /* Otherwise (wValue == 0), reset all features of all EP's */
-+ else {
-+ /* Traverse all the active EP's and reset the feature(s) value(s) */
-+ //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
-+ DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
-+ cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+ retval = cfi_reset_concat_val(cfiep);
-+ if (retval < 0) {
-+ CFI_INFO
-+ ("%s: Error resetting the feature Concatenation Value\n",
-+ __func__);
-+ return retval;
-+ }
-+ }
-+ }
-+ return retval;
-+}
-+
-+static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
-+{
-+ int retval = 0;
-+ cfi_ep_t *cfiep;
-+ cfiobject_t *cfi = pcd->cfi;
-+ dwc_list_link_t *tmp;
-+
-+ /* If the EP address is known then reset the features for only that EP */
-+ if (addr) {
-+ cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == cfiep) {
-+ CFI_INFO("%s: Error getting the EP address 0x%02x\n",
-+ __func__, addr);
-+ return -DWC_E_INVALID;
-+ }
-+ retval = cfi_reset_align_val(cfiep);
-+ }
-+ /* Otherwise (wValue == 0), reset all features of all EP's */
-+ else {
-+ /* Traverse all the active EP's and reset the feature(s) value(s) */
-+ //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
-+ DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
-+ cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+ retval = cfi_reset_align_val(cfiep);
-+ if (retval < 0) {
-+ CFI_INFO
-+ ("%s: Error resetting the feature Aliignment Value\n",
-+ __func__);
-+ return retval;
-+ }
-+ }
-+ }
-+ return retval;
-+
-+}
-+
-+static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req)
-+{
-+ int retval = 0;
-+
-+ switch (req->wIndex) {
-+ case 0:
-+ /* Reset all features */
-+ retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
-+ break;
-+
-+ case FT_ID_DMA_BUFFER_SETUP:
-+ /* Reset the SG buffer setup */
-+ retval =
-+ cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
-+ break;
-+
-+ case FT_ID_DMA_CONCAT_SETUP:
-+ /* Reset the Concatenation buffer setup */
-+ retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
-+ break;
-+
-+ case FT_ID_DMA_BUFF_ALIGN:
-+ /* Reset the Alignment buffer setup */
-+ retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
-+ break;
-+
-+ case FT_ID_TX_FIFO_DEPTH:
-+ retval =
-+ cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
-+ pcd->cfi->need_gadget_att = 0;
-+ break;
-+
-+ case FT_ID_RX_FIFO_DEPTH:
-+ retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
-+ pcd->cfi->need_gadget_att = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+ return retval;
-+}
-+
-+/**
-+ * This function sets a new value for the SG buffer setup.
-+ */
-+static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
-+{
-+ uint8_t inaddr, outaddr;
-+ cfi_ep_t *epin, *epout;
-+ ddma_sg_buffer_setup_t *psgval;
-+ uint32_t desccount, size;
-+
-+ CFI_INFO("%s\n", __func__);
-+
-+ psgval = (ddma_sg_buffer_setup_t *) buf;
-+ desccount = (uint32_t) psgval->bCount;
-+ size = (uint32_t) psgval->wSize;
-+
-+ /* Check the DMA descriptor count */
-+ if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
-+ CFI_INFO
-+ ("%s: The count of DMA Descriptors should be between 1 and %d\n",
-+ __func__, MAX_DMA_DESCS_PER_EP);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ /* Check the DMA descriptor count */
-+
-+ if (size == 0) {
-+
-+ CFI_INFO("%s: The transfer size should be at least 1 byte\n",
-+ __func__);
-+
-+ return -DWC_E_INVALID;
-+
-+ }
-+
-+ inaddr = psgval->bInEndpointAddress;
-+ outaddr = psgval->bOutEndpointAddress;
-+
-+ epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
-+ epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
-+
-+ if (NULL == epin || NULL == epout) {
-+ CFI_INFO
-+ ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
-+ __func__, inaddr, outaddr);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ epin->ep->dwc_ep.buff_mode = BM_SG;
-+ dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
-+
-+ epout->ep->dwc_ep.buff_mode = BM_SG;
-+ dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function sets a new value for the buffer Alignment setup.
-+ */
-+static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
-+{
-+ cfi_ep_t *ep;
-+ uint8_t addr;
-+ ddma_align_buffer_setup_t *palignval;
-+
-+ palignval = (ddma_align_buffer_setup_t *) buf;
-+ addr = palignval->bEndpointAddress;
-+
-+ ep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
-+ __func__, addr);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ ep->ep->dwc_ep.buff_mode = BM_ALIGN;
-+ dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function sets a new value for the Concatenation buffer setup.
-+ */
-+static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
-+{
-+ uint8_t addr;
-+ cfi_ep_t *ep;
-+ struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
-+ uint16_t *pVals;
-+ uint32_t desccount;
-+ int i;
-+ uint16_t mps;
-+
-+ pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
-+ desccount = (uint32_t) pConcatValHdr->bDescCount;
-+ pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
-+
-+ /* Check the DMA descriptor count */
-+ if (desccount > MAX_DMA_DESCS_PER_EP) {
-+ CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
-+ __func__, MAX_DMA_DESCS_PER_EP);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ addr = pConcatValHdr->bEndpointAddress;
-+ ep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
-+ __func__, addr);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ mps = UGETW(ep->ep->desc->wMaxPacketSize);
-+
-+#if 0
-+ for (i = 0; i < desccount; i++) {
-+ CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
-+ }
-+ CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
-+#endif
-+
-+ /* Check the wTxSizes to be less than or equal to the mps */
-+ for (i = 0; i < desccount; i++) {
-+ if (pVals[i] > mps) {
-+ CFI_INFO
-+ ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
-+ __func__, i, pVals[i]);
-+ return -DWC_E_INVALID;
-+ }
-+ }
-+
-+ ep->ep->dwc_ep.buff_mode = BM_CONCAT;
-+ dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
-+
-+ /* Free the previously allocated storage for the wTxBytes */
-+ if (ep->bm_concat->wTxBytes) {
-+ DWC_FREE(ep->bm_concat->wTxBytes);
-+ }
-+
-+ /* Allocate a new storage for the wTxBytes field */
-+ ep->bm_concat->wTxBytes =
-+ DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
-+ if (NULL == ep->bm_concat->wTxBytes) {
-+ CFI_INFO("%s: Unable to allocate memory\n", __func__);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ /* Copy the new values into the wTxBytes filed */
-+ dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
-+ sizeof(uint16_t) * pConcatValHdr->bDescCount);
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function calculates the total of all FIFO sizes
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ * @return The total of data FIFO sizes.
-+ *
-+ */
-+static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_params_t *params = core_if->core_params;
-+ uint16_t dfifo_total = 0;
-+ int i;
-+
-+ /* The shared RxFIFO size */
-+ dfifo_total =
-+ params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
-+
-+ /* Add up each TxFIFO size to the total */
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ dfifo_total += params->dev_tx_fifo_size[i];
-+ }
-+
-+ return dfifo_total;
-+}
-+
-+/**
-+ * This function returns Rx FIFO size
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ * @return The total of data FIFO sizes.
-+ *
-+ */
-+static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
-+{
-+ switch (wValue >> 8) {
-+ case 0:
-+ return (core_if->pwron_rxfsiz <
-+ 32768) ? core_if->pwron_rxfsiz : 32768;
-+ break;
-+ case 1:
-+ return core_if->core_params->dev_rx_fifo_size;
-+ break;
-+ default:
-+ return -DWC_E_INVALID;
-+ break;
-+ }
-+}
-+
-+/**
-+ * This function returns Tx FIFO size for IN EP
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ * @return The total of data FIFO sizes.
-+ *
-+ */
-+static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+
-+ ep = get_ep_by_addr(pcd, wValue & 0xff);
-+
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
-+ __func__, wValue & 0xff);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (!ep->dwc_ep.is_in) {
-+ CFI_INFO
-+ ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
-+ __func__, wValue & 0xff);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ switch (wValue >> 8) {
-+ case 0:
-+ return (GET_CORE_IF(pcd)->pwron_txfsiz
-+ [ep->dwc_ep.tx_fifo_num - 1] <
-+ 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
-+ dwc_ep.tx_fifo_num
-+ - 1] : 32768;
-+ break;
-+ case 1:
-+ return GET_CORE_IF(pcd)->core_params->
-+ dev_tx_fifo_size[ep->dwc_ep.num - 1];
-+ break;
-+ default:
-+ return -DWC_E_INVALID;
-+ break;
-+ }
-+}
-+
-+/**
-+ * This function checks if the submitted combination of
-+ * device mode FIFO sizes is possible or not.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ * @return 1 if possible, 0 otherwise.
-+ *
-+ */
-+static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
-+{
-+ uint16_t dfifo_actual = 0;
-+ dwc_otg_core_params_t *params = core_if->core_params;
-+ uint16_t start_addr = 0;
-+ int i;
-+
-+ dfifo_actual =
-+ params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ dfifo_actual += params->dev_tx_fifo_size[i];
-+ }
-+
-+ if (dfifo_actual > core_if->total_fifo_size) {
-+ return 0;
-+ }
-+
-+ if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
-+ return 0;
-+
-+ if (params->dev_nperio_tx_fifo_size > 32768
-+ || params->dev_nperio_tx_fifo_size < 16)
-+ return 0;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+
-+ if (params->dev_tx_fifo_size[i] > 768
-+ || params->dev_tx_fifo_size[i] < 4)
-+ return 0;
-+ }
-+
-+ if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
-+ return 0;
-+ start_addr = params->dev_rx_fifo_size;
-+
-+ if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
-+ return 0;
-+ start_addr += params->dev_nperio_tx_fifo_size;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+
-+ if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
-+ return 0;
-+ start_addr += params->dev_tx_fifo_size[i];
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * This function resizes Device mode FIFOs
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ * @return 1 if successful, 0 otherwise
-+ *
-+ */
-+static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
-+{
-+ int i = 0;
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ dwc_otg_core_params_t *params = core_if->core_params;
-+ uint32_t rx_fifo_size;
-+ fifosize_data_t nptxfifosize;
-+ fifosize_data_t txfifosize[15];
-+
-+ uint32_t rx_fsz_bak;
-+ uint32_t nptxfsz_bak;
-+ uint32_t txfsz_bak[15];
-+
-+ uint16_t start_address;
-+ uint8_t retval = 1;
-+
-+ if (!check_fifo_sizes(core_if)) {
-+ return 0;
-+ }
-+
-+ /* Configure data FIFO sizes */
-+ if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
-+ rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
-+ rx_fifo_size = params->dev_rx_fifo_size;
-+ DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
-+
-+ /*
-+ * Tx FIFOs These FIFOs are numbered from 1 to 15.
-+ * Indexes of the FIFO size module parameters in the
-+ * dev_tx_fifo_size array and the FIFO size registers in
-+ * the dtxfsiz array run from 0 to 14.
-+ */
-+
-+ /* Non-periodic Tx FIFO */
-+ nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
-+ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
-+ start_address = params->dev_rx_fifo_size;
-+ nptxfifosize.b.startaddr = start_address;
-+
-+ DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
-+
-+ start_address += nptxfifosize.b.depth;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
-+
-+ txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
-+ txfifosize[i].b.startaddr = start_address;
-+ DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
-+ txfifosize[i].d32);
-+
-+ start_address += txfifosize[i].b.depth;
-+ }
-+
-+ /** Check if register values are set correctly */
-+ if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
-+ retval = 0;
-+ }
-+
-+ if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
-+ retval = 0;
-+ }
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ if (txfifosize[i].d32 !=
-+ DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
-+ retval = 0;
-+ }
-+ }
-+
-+ /** If register values are not set correctly, reset old values */
-+ if (retval == 0) {
-+ DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
-+
-+ /* Non-periodic Tx FIFO */
-+ DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
-+ txfsz_bak[i]);
-+ }
-+ }
-+ } else {
-+ return 0;
-+ }
-+
-+ /* Flush the FIFOs */
-+ dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
-+ dwc_otg_flush_rx_fifo(core_if);
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function sets a new value for the buffer Alignment setup.
-+ */
-+static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
-+{
-+ int retval;
-+ uint32_t fsiz;
-+ uint16_t size;
-+ uint16_t ep_addr;
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
-+ tx_fifo_size_setup_t *ptxfifoval;
-+
-+ ptxfifoval = (tx_fifo_size_setup_t *) buf;
-+ ep_addr = ptxfifoval->bEndpointAddress;
-+ size = ptxfifoval->wDepth;
-+
-+ ep = get_ep_by_addr(pcd, ep_addr);
-+
-+ CFI_INFO
-+ ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
-+ __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
-+
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
-+ __func__, ep_addr);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
-+ params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
-+
-+ if (resize_fifos(GET_CORE_IF(pcd))) {
-+ retval = 0;
-+ } else {
-+ CFI_INFO
-+ ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
-+ __func__, ep_addr);
-+ params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function sets a new value for the buffer Alignment setup.
-+ */
-+static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
-+{
-+ int retval;
-+ uint32_t fsiz;
-+ uint16_t size;
-+ dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
-+ rx_fifo_size_setup_t *prxfifoval;
-+
-+ prxfifoval = (rx_fifo_size_setup_t *) buf;
-+ size = prxfifoval->wDepth;
-+
-+ fsiz = params->dev_rx_fifo_size;
-+ params->dev_rx_fifo_size = size;
-+
-+ if (resize_fifos(GET_CORE_IF(pcd))) {
-+ retval = 0;
-+ } else {
-+ CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
-+ __func__);
-+ params->dev_rx_fifo_size = fsiz;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function reads the SG of an EP's buffer setup into the buffer buf
-+ */
-+static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req)
-+{
-+ int retval = -DWC_E_INVALID;
-+ uint8_t addr;
-+ cfi_ep_t *ep;
-+
-+ /* The Low Byte of the wValue contains a non-zero address of the endpoint */
-+ addr = req->wValue & 0xFF;
-+ if (addr == 0) /* The address should be non-zero */
-+ return retval;
-+
-+ ep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
-+ __func__, addr);
-+ return retval;
-+ }
-+
-+ dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
-+ retval = BS_SG_VAL_DESC_LEN;
-+ return retval;
-+}
-+
-+/**
-+ * This function reads the Concatenation value of an EP's buffer mode into
-+ * the buffer buf
-+ */
-+static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req)
-+{
-+ int retval = -DWC_E_INVALID;
-+ uint8_t addr;
-+ cfi_ep_t *ep;
-+ uint8_t desc_count;
-+
-+ /* The Low Byte of the wValue contains a non-zero address of the endpoint */
-+ addr = req->wValue & 0xFF;
-+ if (addr == 0) /* The address should be non-zero */
-+ return retval;
-+
-+ ep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
-+ __func__, addr);
-+ return retval;
-+ }
-+
-+ /* Copy the header to the buffer */
-+ dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
-+ /* Advance the buffer pointer by the header size */
-+ buf += BS_CONCAT_VAL_HDR_LEN;
-+
-+ desc_count = ep->bm_concat->hdr.bDescCount;
-+ /* Copy alll the wTxBytes to the buffer */
-+ dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
-+
-+ retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
-+ return retval;
-+}
-+
-+/**
-+ * This function reads the buffer Alignment value of an EP's buffer mode into
-+ * the buffer buf
-+ *
-+ * @return The total number of bytes copied to the buffer or negative error code.
-+ */
-+static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
-+ struct cfi_usb_ctrlrequest *req)
-+{
-+ int retval = -DWC_E_INVALID;
-+ uint8_t addr;
-+ cfi_ep_t *ep;
-+
-+ /* The Low Byte of the wValue contains a non-zero address of the endpoint */
-+ addr = req->wValue & 0xFF;
-+ if (addr == 0) /* The address should be non-zero */
-+ return retval;
-+
-+ ep = get_cfi_ep_by_addr(pcd->cfi, addr);
-+ if (NULL == ep) {
-+ CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
-+ __func__, addr);
-+ return retval;
-+ }
-+
-+ dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
-+ retval = BS_ALIGN_VAL_HDR_LEN;
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function sets a new value for the specified feature
-+ *
-+ * @param pcd A pointer to the PCD object
-+ *
-+ * @return 0 if successful, negative error code otherwise to stall the DCE.
-+ */
-+static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
-+{
-+ int retval = -DWC_E_NOT_SUPPORTED;
-+ uint16_t wIndex, wValue;
-+ uint8_t bRequest;
-+ struct dwc_otg_core_if *coreif;
-+ cfiobject_t *cfi = pcd->cfi;
-+ struct cfi_usb_ctrlrequest *ctrl_req;
-+ uint8_t *buf;
-+ ctrl_req = &cfi->ctrl_req;
-+
-+ buf = pcd->cfi->ctrl_req.data;
-+
-+ coreif = GET_CORE_IF(pcd);
-+ bRequest = ctrl_req->bRequest;
-+ wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
-+ wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
-+
-+ /* See which feature is to be modified */
-+ switch (wIndex) {
-+ case FT_ID_DMA_BUFFER_SETUP:
-+ /* Modify the feature */
-+ if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
-+ return retval;
-+
-+ /* And send this request to the gadget */
-+ cfi->need_gadget_att = 1;
-+ break;
-+
-+ case FT_ID_DMA_BUFF_ALIGN:
-+ if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
-+ return retval;
-+ cfi->need_gadget_att = 1;
-+ break;
-+
-+ case FT_ID_DMA_CONCAT_SETUP:
-+ /* Modify the feature */
-+ if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
-+ return retval;
-+ cfi->need_gadget_att = 1;
-+ break;
-+
-+ case FT_ID_DMA_CIRCULAR:
-+ CFI_INFO("FT_ID_DMA_CIRCULAR\n");
-+ break;
-+
-+ case FT_ID_THRESHOLD_SETUP:
-+ CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
-+ break;
-+
-+ case FT_ID_DFIFO_DEPTH:
-+ CFI_INFO("FT_ID_DFIFO_DEPTH\n");
-+ break;
-+
-+ case FT_ID_TX_FIFO_DEPTH:
-+ CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
-+ if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
-+ return retval;
-+ cfi->need_gadget_att = 0;
-+ break;
-+
-+ case FT_ID_RX_FIFO_DEPTH:
-+ CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
-+ if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
-+ return retval;
-+ cfi->need_gadget_att = 0;
-+ break;
-+ }
-+
-+ return retval;
-+}
-+
-+#endif //DWC_UTE_CFI
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cfi.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cfi.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cfi.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,320 @@
-+/* ==========================================================================
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#if !defined(__DWC_OTG_CFI_H__)
-+#define __DWC_OTG_CFI_H__
-+
-+#include "dwc_otg_pcd.h"
-+#include "dwc_cfi_common.h"
-+
-+/**
-+ * @file
-+ * This file contains the CFI related OTG PCD specific common constants,
-+ * interfaces(functions and macros) and data structures.The CFI Protocol is an
-+ * optional interface for internal testing purposes that a DUT may implement to
-+ * support testing of configurable features.
-+ *
-+ */
-+
-+struct dwc_otg_pcd;
-+struct dwc_otg_pcd_ep;
-+
-+/** OTG CFI Features (properties) ID constants */
-+/** This is a request for all Core Features */
-+#define FT_ID_DMA_MODE 0x0001
-+#define FT_ID_DMA_BUFFER_SETUP 0x0002
-+#define FT_ID_DMA_BUFF_ALIGN 0x0003
-+#define FT_ID_DMA_CONCAT_SETUP 0x0004
-+#define FT_ID_DMA_CIRCULAR 0x0005
-+#define FT_ID_THRESHOLD_SETUP 0x0006
-+#define FT_ID_DFIFO_DEPTH 0x0007
-+#define FT_ID_TX_FIFO_DEPTH 0x0008
-+#define FT_ID_RX_FIFO_DEPTH 0x0009
-+
-+/**********************************************************/
-+#define CFI_INFO_DEF
-+
-+#ifdef CFI_INFO_DEF
-+#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt);
-+#else
-+#define CFI_INFO(fmt...)
-+#endif
-+
-+#define min(x,y) ({ \
-+ x < y ? x : y; })
-+
-+#define max(x,y) ({ \
-+ x > y ? x : y; })
-+
-+/**
-+ * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
-+ * also used for setting up a buffer for Circular DDMA.
-+ */
-+struct _ddma_sg_buffer_setup {
-+#define BS_SG_VAL_DESC_LEN 6
-+ /* The OUT EP address */
-+ uint8_t bOutEndpointAddress;
-+ /* The IN EP address */
-+ uint8_t bInEndpointAddress;
-+ /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
-+ uint8_t bOffset;
-+ /* The number of transfer segments (a DMA descriptors per each segment) */
-+ uint8_t bCount;
-+ /* Size (in byte) of each transfer segment */
-+ uint16_t wSize;
-+} __attribute__ ((packed));
-+typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
-+
-+/** Descriptor DMA Concatenation Buffer setup structure */
-+struct _ddma_concat_buffer_setup_hdr {
-+#define BS_CONCAT_VAL_HDR_LEN 4
-+ /* The endpoint for which the buffer is to be set up */
-+ uint8_t bEndpointAddress;
-+ /* The count of descriptors to be used */
-+ uint8_t bDescCount;
-+ /* The total size of the transfer */
-+ uint16_t wSize;
-+} __attribute__ ((packed));
-+typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
-+
-+/** Descriptor DMA Concatenation Buffer setup structure */
-+struct _ddma_concat_buffer_setup {
-+ /* The SG header */
-+ ddma_concat_buffer_setup_hdr_t hdr;
-+
-+ /* The XFER sizes pointer (allocated dynamically) */
-+ uint16_t *wTxBytes;
-+} __attribute__ ((packed));
-+typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
-+
-+/** Descriptor DMA Alignment Buffer setup structure */
-+struct _ddma_align_buffer_setup {
-+#define BS_ALIGN_VAL_HDR_LEN 2
-+ uint8_t bEndpointAddress;
-+ uint8_t bAlign;
-+} __attribute__ ((packed));
-+typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
-+
-+/** Transmit FIFO Size setup structure */
-+struct _tx_fifo_size_setup {
-+ uint8_t bEndpointAddress;
-+ uint16_t wDepth;
-+} __attribute__ ((packed));
-+typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
-+
-+/** Transmit FIFO Size setup structure */
-+struct _rx_fifo_size_setup {
-+ uint16_t wDepth;
-+} __attribute__ ((packed));
-+typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
-+
-+/**
-+ * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
-+ * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
-+ * to the data returned in the data stage of a 3-stage Control Write requests.
-+ */
-+struct cfi_usb_ctrlrequest {
-+ uint8_t bRequestType;
-+ uint8_t bRequest;
-+ uint16_t wValue;
-+ uint16_t wIndex;
-+ uint16_t wLength;
-+ uint8_t *data;
-+} UPACKED;
-+
-+/*---------------------------------------------------------------------------*/
-+
-+/**
-+ * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
-+ * This structure is used to store the buffer setup data for any
-+ * enabled endpoint in the PCD.
-+ */
-+struct cfi_ep {
-+ /* Entry for the list container */
-+ dwc_list_link_t lh;
-+ /* Pointer to the active PCD endpoint structure */
-+ struct dwc_otg_pcd_ep *ep;
-+ /* The last descriptor in the chain of DMA descriptors of the endpoint */
-+ struct dwc_otg_dma_desc *dma_desc_last;
-+ /* The SG feature value */
-+ ddma_sg_buffer_setup_t *bm_sg;
-+ /* The Circular feature value */
-+ ddma_sg_buffer_setup_t *bm_circ;
-+ /* The Concatenation feature value */
-+ ddma_concat_buffer_setup_t *bm_concat;
-+ /* The Alignment feature value */
-+ ddma_align_buffer_setup_t *bm_align;
-+ /* XFER length */
-+ uint32_t xfer_len;
-+ /*
-+ * Count of DMA descriptors currently used.
-+ * The total should not exceed the MAX_DMA_DESCS_PER_EP value
-+ * defined in the dwc_otg_cil.h
-+ */
-+ uint32_t desc_count;
-+};
-+typedef struct cfi_ep cfi_ep_t;
-+
-+typedef struct cfi_dma_buff {
-+#define CFI_IN_BUF_LEN 1024
-+#define CFI_OUT_BUF_LEN 1024
-+ dma_addr_t addr;
-+ uint8_t *buf;
-+} cfi_dma_buff_t;
-+
-+struct cfiobject;
-+
-+/**
-+ * This is the interface for the CFI operations.
-+ *
-+ * @param ep_enable Called when any endpoint is enabled and activated.
-+ * @param release Called when the CFI object is released and it needs to correctly
-+ * deallocate the dynamic memory
-+ * @param ctrl_write_complete Called when the data stage of the request is complete
-+ */
-+typedef struct cfi_ops {
-+ int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
-+ struct dwc_otg_pcd_ep * ep);
-+ void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
-+ struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
-+ unsigned size, gfp_t flags);
-+ void (*release) (struct cfiobject * cfi);
-+ int (*ctrl_write_complete) (struct cfiobject * cfi,
-+ struct dwc_otg_pcd * pcd);
-+ void (*build_descriptors) (struct cfiobject * cfi,
-+ struct dwc_otg_pcd * pcd,
-+ struct dwc_otg_pcd_ep * ep,
-+ dwc_otg_pcd_request_t * req);
-+} cfi_ops_t;
-+
-+struct cfiobject {
-+ cfi_ops_t ops;
-+ struct dwc_otg_pcd *pcd;
-+ struct usb_gadget *gadget;
-+
-+ /* Buffers used to send/receive CFI-related request data */
-+ cfi_dma_buff_t buf_in;
-+ cfi_dma_buff_t buf_out;
-+
-+ /* CFI specific Control request wrapper */
-+ struct cfi_usb_ctrlrequest ctrl_req;
-+
-+ /* The list of active EP's in the PCD of type cfi_ep_t */
-+ dwc_list_link_t active_eps;
-+
-+ /* This flag shall control the propagation of a specific request
-+ * to the gadget's processing routines.
-+ * 0 - no gadget handling
-+ * 1 - the gadget needs to know about this request (w/o completing a status
-+ * phase - just return a 0 to the _setup callback)
-+ */
-+ uint8_t need_gadget_att;
-+
-+ /* Flag indicating whether the status IN phase needs to be
-+ * completed by the PCD
-+ */
-+ uint8_t need_status_in_complete;
-+};
-+typedef struct cfiobject cfiobject_t;
-+
-+#define DUMP_MSG
-+
-+#if defined(DUMP_MSG)
-+static inline void dump_msg(const u8 * buf, unsigned int length)
-+{
-+ unsigned int start, num, i;
-+ char line[52], *p;
-+
-+ if (length >= 512)
-+ return;
-+
-+ start = 0;
-+ while (length > 0) {
-+ num = min(length, 16u);
-+ p = line;
-+ for (i = 0; i < num; ++i) {
-+ if (i == 8)
-+ *p++ = ' ';
-+ DWC_SPRINTF(p, " %02x", buf[i]);
-+ p += 3;
-+ }
-+ *p = 0;
-+ DWC_DEBUG("%6x: %s\n", start, line);
-+ buf += num;
-+ start += num;
-+ length -= num;
-+ }
-+}
-+#else
-+static inline void dump_msg(const u8 * buf, unsigned int length)
-+{
-+}
-+#endif
-+
-+/**
-+ * This function returns a pointer to cfi_ep_t object with the addr address.
-+ */
-+static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
-+ uint8_t addr)
-+{
-+ struct cfi_ep *pcfiep;
-+ dwc_list_link_t *tmp;
-+
-+ DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
-+ pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+
-+ if (pcfiep->ep->desc->bEndpointAddress == addr) {
-+ return pcfiep;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+/**
-+ * This function returns a pointer to cfi_ep_t object that matches
-+ * the dwc_otg_pcd_ep object.
-+ */
-+static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
-+ struct dwc_otg_pcd_ep *ep)
-+{
-+ struct cfi_ep *pcfiep = NULL;
-+ dwc_list_link_t *tmp;
-+
-+ DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
-+ pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
-+ if (pcfiep->ep == ep) {
-+ return pcfiep;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
-+
-+#endif /* (__DWC_OTG_CFI_H__) */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cil.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cil.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cil.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cil.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,7151 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
-+ * $Revision: #191 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+/** @file
-+ *
-+ * The Core Interface Layer provides basic services for accessing and
-+ * managing the DWC_otg hardware. These services are used by both the
-+ * Host Controller Driver and the Peripheral Controller Driver.
-+ *
-+ * The CIL manages the memory map for the core so that the HCD and PCD
-+ * don't have to do this separately. It also handles basic tasks like
-+ * reading/writing the registers and data FIFOs in the controller.
-+ * Some of the data access functions provide encapsulation of several
-+ * operations required to perform a task, such as writing multiple
-+ * registers to start a transfer. Finally, the CIL performs basic
-+ * services that are not specific to either the host or device modes
-+ * of operation. These services include management of the OTG Host
-+ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
-+ * Diagnostic API is also provided to allow testing of the controller
-+ * hardware.
-+ *
-+ * The Core Interface Layer has the following requirements:
-+ * - Provides basic controller operations.
-+ * - Minimal use of OS services.
-+ * - The OS services used will be abstracted by using inline functions
-+ * or macros.
-+ *
-+ */
-+
-+#include "dwc_os.h"
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_cil.h"
-+
-+static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * This function is called to initialize the DWC_otg CSR data
-+ * structures. The register addresses in the device and host
-+ * structures are initialized from the base address supplied by the
-+ * caller. The calling function must make the OS calls to get the
-+ * base address of the DWC_otg controller registers. The core_params
-+ * argument holds the parameters that specify how the core should be
-+ * configured.
-+ *
-+ * @param reg_base_addr Base address of DWC_otg core registers
-+ *
-+ */
-+dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
-+{
-+ dwc_otg_core_if_t *core_if = 0;
-+ dwc_otg_dev_if_t *dev_if = 0;
-+ dwc_otg_host_if_t *host_if = 0;
-+ uint8_t *reg_base = (uint8_t *) reg_base_addr;
-+ int i = 0;
-+
-+ DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
-+
-+ core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
-+
-+ if (core_if == NULL) {
-+ DWC_DEBUGPL(DBG_CIL,
-+ "Allocation of dwc_otg_core_if_t failed\n");
-+ return 0;
-+ }
-+ core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
-+
-+ /*
-+ * Allocate the Device Mode structures.
-+ */
-+ dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
-+
-+ if (dev_if == NULL) {
-+ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
-+ DWC_FREE(core_if);
-+ return 0;
-+ }
-+
-+ dev_if->dev_global_regs =
-+ (dwc_otg_device_global_regs_t *) (reg_base +
-+ DWC_DEV_GLOBAL_REG_OFFSET);
-+
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
-+ (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
-+ (i * DWC_EP_REG_OFFSET));
-+
-+ dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
-+ (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
-+ (i * DWC_EP_REG_OFFSET));
-+ DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
-+ i, &dev_if->in_ep_regs[i]->diepctl);
-+ DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
-+ i, &dev_if->out_ep_regs[i]->doepctl);
-+ }
-+
-+ dev_if->speed = 0; // unknown
-+
-+ core_if->dev_if = dev_if;
-+
-+ /*
-+ * Allocate the Host Mode structures.
-+ */
-+ host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
-+
-+ if (host_if == NULL) {
-+ DWC_DEBUGPL(DBG_CIL,
-+ "Allocation of dwc_otg_host_if_t failed\n");
-+ DWC_FREE(dev_if);
-+ DWC_FREE(core_if);
-+ return 0;
-+ }
-+
-+ host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
-+ (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
-+
-+ host_if->hprt0 =
-+ (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
-+
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
-+ (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
-+ (i * DWC_OTG_CHAN_REGS_OFFSET));
-+ DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
-+ i, &host_if->hc_regs[i]->hcchar);
-+ }
-+
-+ host_if->num_host_channels = MAX_EPS_CHANNELS;
-+ core_if->host_if = host_if;
-+
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ core_if->data_fifo[i] =
-+ (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
-+ (i * DWC_OTG_DATA_FIFO_SIZE));
-+ DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
-+ i, (unsigned long)core_if->data_fifo[i]);
-+ }
-+
-+ core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
-+
-+ /* Initiate lx_state to L3 disconnected state */
-+ core_if->lx_state = DWC_OTG_L3;
-+ /*
-+ * Store the contents of the hardware configuration registers here for
-+ * easy access later.
-+ */
-+ core_if->hwcfg1.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
-+ core_if->hwcfg2.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
-+ core_if->hwcfg3.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
-+ core_if->hwcfg4.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
-+
-+ /* Force host mode to get HPTXFSIZ exact power on value */
-+ {
-+ gusbcfg_data_t gusbcfg = {.d32 = 0 };
-+ gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ gusbcfg.b.force_host_mode = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
-+ dwc_mdelay(100);
-+ core_if->hptxfsiz.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
-+ gusbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ gusbcfg.b.force_host_mode = 0;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
-+ dwc_mdelay(100);
-+ }
-+
-+ DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
-+ DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
-+ DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
-+ DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
-+
-+ core_if->hcfg.d32 =
-+ DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
-+ core_if->dcfg.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+
-+ DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
-+ DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
-+
-+ DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
-+ DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
-+ DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
-+ DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
-+ core_if->hwcfg2.b.num_host_chan);
-+ DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
-+ core_if->hwcfg2.b.nonperio_tx_q_depth);
-+ DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
-+ core_if->hwcfg2.b.host_perio_tx_q_depth);
-+ DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
-+ core_if->hwcfg2.b.dev_token_q_depth);
-+
-+ DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
-+ core_if->hwcfg3.b.dfifo_depth);
-+ DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
-+ core_if->hwcfg3.b.xfer_size_cntr_width);
-+
-+ /*
-+ * Set the SRP sucess bit for FS-I2c
-+ */
-+ core_if->srp_success = 0;
-+ core_if->srp_timer_started = 0;
-+
-+ /*
-+ * Create new workqueue and init works
-+ */
-+ core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
-+ if (core_if->wq_otg == 0) {
-+ DWC_WARN("DWC_WORKQ_ALLOC failed\n");
-+ DWC_FREE(host_if);
-+ DWC_FREE(dev_if);
-+ DWC_FREE(core_if);
-+ return 0;
-+ }
-+
-+ core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
-+
-+ DWC_PRINTF("Core Release: %x.%x%x%x\n",
-+ (core_if->snpsid >> 12 & 0xF),
-+ (core_if->snpsid >> 8 & 0xF),
-+ (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
-+
-+ core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
-+ w_wakeup_detected, core_if);
-+ if (core_if->wkp_timer == 0) {
-+ DWC_WARN("DWC_TIMER_ALLOC failed\n");
-+ DWC_FREE(host_if);
-+ DWC_FREE(dev_if);
-+ DWC_WORKQ_FREE(core_if->wq_otg);
-+ DWC_FREE(core_if);
-+ return 0;
-+ }
-+
-+ if (dwc_otg_setup_params(core_if)) {
-+ DWC_WARN("Error while setting core params\n");
-+ }
-+
-+ core_if->hibernation_suspend = 0;
-+
-+ /** ADP initialization */
-+ dwc_otg_adp_init(core_if);
-+
-+ return core_if;
-+}
-+
-+/**
-+ * This function frees the structures allocated by dwc_otg_cil_init().
-+ *
-+ * @param core_if The core interface pointer returned from
-+ * dwc_otg_cil_init().
-+ *
-+ */
-+void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
-+{
-+ dctl_data_t dctl = {.d32 = 0 };
-+ DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
-+
-+ /* Disable all interrupts */
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
-+
-+ dctl.b.sftdiscon = 1;
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
-+ dctl.d32);
-+ }
-+
-+ if (core_if->wq_otg) {
-+ DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
-+ DWC_WORKQ_FREE(core_if->wq_otg);
-+ }
-+ if (core_if->dev_if) {
-+ DWC_FREE(core_if->dev_if);
-+ }
-+ if (core_if->host_if) {
-+ DWC_FREE(core_if->host_if);
-+ }
-+
-+ /** Remove ADP Stuff */
-+ dwc_otg_adp_remove(core_if);
-+ if (core_if->core_params) {
-+ DWC_FREE(core_if->core_params);
-+ }
-+ if (core_if->wkp_timer) {
-+ DWC_TIMER_FREE(core_if->wkp_timer);
-+ }
-+ if (core_if->srp_timer) {
-+ DWC_TIMER_FREE(core_if->srp_timer);
-+ }
-+ DWC_FREE(core_if);
-+}
-+
-+/**
-+ * This function enables the controller's Global Interrupt in the AHB Config
-+ * register.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ gahbcfg_data_t ahbcfg = {.d32 = 0 };
-+ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
-+}
-+
-+/**
-+ * This function disables the controller's Global Interrupt in the AHB Config
-+ * register.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ gahbcfg_data_t ahbcfg = {.d32 = 0 };
-+ ahbcfg.b.glblintrmsk = 1; /* Disable interrupts */
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
-+}
-+
-+/**
-+ * This function initializes the commmon interrupts, used in both
-+ * device and host modes.
-+ *
-+ * @param core_if Programming view of the DWC_otg controller
-+ *
-+ */
-+static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ /* Clear any pending OTG Interrupts */
-+ DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
-+
-+ /* Clear any pending interrupts */
-+ DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /*
-+ * Enable the interrupts in the GINTMSK.
-+ */
-+ intr_mask.b.modemismatch = 1;
-+ intr_mask.b.otgintr = 1;
-+
-+ if (!core_if->dma_enable) {
-+ intr_mask.b.rxstsqlvl = 1;
-+ }
-+
-+ intr_mask.b.conidstschng = 1;
-+ intr_mask.b.wkupintr = 1;
-+ intr_mask.b.disconnect = 0;
-+ intr_mask.b.usbsuspend = 1;
-+ intr_mask.b.sessreqintr = 1;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ if (core_if->core_params->lpm_enable) {
-+ intr_mask.b.lpmtranrcvd = 1;
-+ }
-+#endif
-+ DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
-+}
-+
-+/*
-+ * The restore operation is modified to support Synopsys Emulated Powerdown and
-+ * Hibernation. This function is for exiting from Device mode hibernation by
-+ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
-+ * @param reset - indicates whether resume is initiated by Reset.
-+ */
-+int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
-+ int rem_wakeup, int reset)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ dctl_data_t dctl = {.d32 = 0 };
-+
-+ int timeout = 2000;
-+
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
-+ /* Switch-on voltage to the core */
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Assert Restore signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.restore = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ if (rem_wakeup) {
-+ dwc_udelay(70);
-+ }
-+
-+ /* Deassert Reset core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Mask interrupts from gpwrdn */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.connect_det_msk = 1;
-+ gpwrdn.b.srp_det_msk = 1;
-+ gpwrdn.b.disconn_det_msk = 1;
-+ gpwrdn.b.rst_det_msk = 1;
-+ gpwrdn.b.lnstchng_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Indicates that we are going out from hibernation */
-+ core_if->hibernation_suspend = 0;
-+
-+ /*
-+ * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
-+ * indicates restore from remote_wakeup
-+ */
-+ restore_essential_regs(core_if, rem_wakeup, 0);
-+
-+ /*
-+ * Wait a little for seeing new value of variable hibernation_suspend if
-+ * Restore done interrupt received before polling
-+ */
-+ dwc_udelay(10);
-+
-+ if (core_if->hibernation_suspend == 0) {
-+ /*
-+ * Wait For Restore_done Interrupt. This mechanism of polling the
-+ * interrupt is introduced to avoid any possible race conditions
-+ */
-+ do {
-+ gintsts_data_t gintsts;
-+ gintsts.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ if (gintsts.b.restoredone) {
-+ gintsts.d32 = 0;
-+ gintsts.b.restoredone = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->
-+ gintsts, gintsts.d32);
-+ DWC_PRINTF("Restore Done Interrupt seen\n");
-+ break;
-+ }
-+ dwc_udelay(10);
-+ } while (--timeout);
-+ if (!timeout) {
-+ DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
-+ }
-+ }
-+ /* Clear all pending interupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* De-assert Restore */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.restore = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ if (!rem_wakeup) {
-+ pcgcctl.d32 = 0;
-+ pcgcctl.b.rstpdwnmodule = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+ }
-+
-+ /* Restore GUSBCFG and DCFG */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
-+ core_if->gr_backup->gusbcfg_local);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
-+ core_if->dr_backup->dcfg);
-+
-+ /* De-assert Wakeup Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ if (!rem_wakeup) {
-+ /* Set Device programming done bit */
-+ dctl.b.pwronprgdone = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ } else {
-+ /* Start Remote Wakeup Signaling */
-+ dctl.d32 = core_if->dr_backup->dctl;
-+ dctl.b.rmtwkupsig = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
-+ }
-+
-+ dwc_mdelay(2);
-+ /* Clear all pending interupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* Restore global registers */
-+ dwc_otg_restore_global_regs(core_if);
-+ /* Restore device global registers */
-+ dwc_otg_restore_dev_regs(core_if, rem_wakeup);
-+
-+ if (rem_wakeup) {
-+ dwc_mdelay(7);
-+ dctl.d32 = 0;
-+ dctl.b.rmtwkupsig = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
-+ }
-+
-+ core_if->hibernation_suspend = 0;
-+ /* The core will be in ON STATE */
-+ core_if->lx_state = DWC_OTG_L0;
-+ DWC_PRINTF("Hibernation recovery completes here\n");
-+
-+ return 1;
-+}
-+
-+/*
-+ * The restore operation is modified to support Synopsys Emulated Powerdown and
-+ * Hibernation. This function is for exiting from Host mode hibernation by
-+ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
-+ * @param reset - indicates whether resume is initiated by Reset.
-+ */
-+int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
-+ int rem_wakeup, int reset)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+
-+ int timeout = 2000;
-+
-+ DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
-+ /* Switch-on voltage to the core */
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Assert Restore signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.restore = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ if (!rem_wakeup) {
-+ dwc_udelay(50);
-+ }
-+
-+ /* Deassert Reset core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.connect_det_msk = 1;
-+ gpwrdn.b.srp_det_msk = 1;
-+ gpwrdn.b.disconn_det_msk = 1;
-+ gpwrdn.b.rst_det_msk = 1;
-+ gpwrdn.b.lnstchng_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Indicates that we are going out from hibernation */
-+ core_if->hibernation_suspend = 0;
-+
-+ /* Set Restore Essential Regs bit in PCGCCTL register */
-+ restore_essential_regs(core_if, rem_wakeup, 1);
-+
-+ /* Wait a little for seeing new value of variable hibernation_suspend if
-+ * Restore done interrupt received before polling */
-+ dwc_udelay(10);
-+
-+ if (core_if->hibernation_suspend == 0) {
-+ /* Wait For Restore_done Interrupt. This mechanism of polling the
-+ * interrupt is introduced to avoid any possible race conditions
-+ */
-+ do {
-+ gintsts_data_t gintsts;
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ if (gintsts.b.restoredone) {
-+ gintsts.d32 = 0;
-+ gintsts.b.restoredone = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+ DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
-+ break;
-+ }
-+ dwc_udelay(10);
-+ } while (--timeout);
-+ if (!timeout) {
-+ DWC_WARN("Restore Done interrupt wasn't generated\n");
-+ }
-+ }
-+
-+ /* Set the flag's value to 0 again after receiving restore done interrupt */
-+ core_if->hibernation_suspend = 0;
-+
-+ /* This step is not described in functional spec but if not wait for this
-+ * delay, mismatch interrupts occurred because just after restore core is
-+ * in Device mode(gintsts.curmode == 0) */
-+ dwc_mdelay(100);
-+
-+ /* Clear all pending interrupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* De-assert Restore */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.restore = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Restore GUSBCFG and HCFG */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
-+ core_if->gr_backup->gusbcfg_local);
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
-+ core_if->hr_backup->hcfg_local);
-+
-+ /* De-assert Wakeup Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Start the Resume operation by programming HPRT0 */
-+ hprt0.d32 = core_if->hr_backup->hprt0_local;
-+ hprt0.b.prtpwr = 1;
-+ hprt0.b.prtena = 0;
-+ hprt0.b.prtsusp = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ DWC_PRINTF("Resume Starts Now\n");
-+ if (!reset) { // Indicates it is Resume Operation
-+ hprt0.d32 = core_if->hr_backup->hprt0_local;
-+ hprt0.b.prtres = 1;
-+ hprt0.b.prtpwr = 1;
-+ hprt0.b.prtena = 0;
-+ hprt0.b.prtsusp = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ if (!rem_wakeup)
-+ hprt0.b.prtres = 0;
-+ /* Wait for Resume time and then program HPRT again */
-+ dwc_mdelay(100);
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ } else { // Indicates it is Reset Operation
-+ hprt0.d32 = core_if->hr_backup->hprt0_local;
-+ hprt0.b.prtrst = 1;
-+ hprt0.b.prtpwr = 1;
-+ hprt0.b.prtena = 0;
-+ hprt0.b.prtsusp = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ /* Wait for Reset time and then program HPRT again */
-+ dwc_mdelay(60);
-+ hprt0.b.prtrst = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ }
-+ /* Clear all interrupt status */
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtconndet = 1;
-+ hprt0.b.prtenchng = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ /* Clear all pending interupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* Restore global registers */
-+ dwc_otg_restore_global_regs(core_if);
-+ /* Restore host global registers */
-+ dwc_otg_restore_host_regs(core_if, reset);
-+
-+ /* The core will be in ON STATE */
-+ core_if->lx_state = DWC_OTG_L0;
-+ DWC_PRINTF("Hibernation recovery is complete here\n");
-+ return 0;
-+}
-+
-+/** Saves some register values into system memory. */
-+int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
-+{
-+ struct dwc_otg_global_regs_backup *gr;
-+ int i;
-+
-+ gr = core_if->gr_backup;
-+ if (!gr) {
-+ gr = DWC_ALLOC(sizeof(*gr));
-+ if (!gr) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ core_if->gr_backup = gr;
-+ }
-+
-+ gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+ gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
-+ gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
-+ gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
-+ gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+#endif
-+ gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
-+ gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
-+ gr->gdfifocfg_local =
-+ DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ gr->dtxfsiz_local[i] =
-+ DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
-+ }
-+
-+ DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl = %08x\n", gr->gotgctl_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg = %08x\n", gr->gahbcfg_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg = %08x\n", gr->gusbcfg_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz = %08x\n", gr->grxfsiz_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
-+ gr->gnptxfsiz_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz = %08x\n",
-+ gr->hptxfsiz_local);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg = %08x\n", gr->glpmcfg_local);
-+#endif
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl = %08x\n", gr->gi2cctl_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl = %08x\n", gr->pcgcctl_local);
-+ DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg = %08x\n",gr->gdfifocfg_local);
-+
-+ return 0;
-+}
-+
-+/** Saves GINTMSK register before setting the msk bits. */
-+int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
-+{
-+ struct dwc_otg_global_regs_backup *gr;
-+
-+ gr = core_if->gr_backup;
-+ if (!gr) {
-+ gr = DWC_ALLOC(sizeof(*gr));
-+ if (!gr) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ core_if->gr_backup = gr;
-+ }
-+
-+ gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+
-+ DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
-+ DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk = %08x\n", gr->gintmsk_local);
-+
-+ return 0;
-+}
-+
-+int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
-+{
-+ struct dwc_otg_dev_regs_backup *dr;
-+ int i;
-+
-+ dr = core_if->dr_backup;
-+ if (!dr) {
-+ dr = DWC_ALLOC(sizeof(*dr));
-+ if (!dr) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ core_if->dr_backup = dr;
-+ }
-+
-+ dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
-+ dr->daintmsk =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
-+ dr->diepmsk =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
-+ dr->doepmsk =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
-+
-+ for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
-+ dr->diepctl[i] =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
-+ dr->dieptsiz[i] =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
-+ dr->diepdma[i] =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
-+ }
-+
-+ DWC_DEBUGPL(DBG_ANY,
-+ "=============Backing Host registers==============\n");
-+ DWC_DEBUGPL(DBG_ANY, "Backed up dcfg = %08x\n", dr->dcfg);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up dctl = %08x\n", dr->dctl);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk = %08x\n",
-+ dr->daintmsk);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk = %08x\n", dr->diepmsk);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk = %08x\n", dr->doepmsk);
-+ for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
-+ DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d] = %08x\n", i,
-+ dr->diepctl[i]);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d] = %08x\n",
-+ i, dr->dieptsiz[i]);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d] = %08x\n", i,
-+ dr->diepdma[i]);
-+ }
-+
-+ return 0;
-+}
-+
-+int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
-+{
-+ struct dwc_otg_host_regs_backup *hr;
-+ int i;
-+
-+ hr = core_if->hr_backup;
-+ if (!hr) {
-+ hr = DWC_ALLOC(sizeof(*hr));
-+ if (!hr) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ core_if->hr_backup = hr;
-+ }
-+
-+ hr->hcfg_local =
-+ DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
-+ hr->haintmsk_local =
-+ DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
-+ for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
-+ hr->hcintmsk_local[i] =
-+ DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
-+ }
-+ hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
-+ hr->hfir_local =
-+ DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
-+
-+ DWC_DEBUGPL(DBG_ANY,
-+ "=============Backing Host registers===============\n");
-+ DWC_DEBUGPL(DBG_ANY, "Backed up hcfg = %08x\n",
-+ hr->hcfg_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
-+ for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
-+ DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
-+ hr->hcintmsk_local[i]);
-+ }
-+ DWC_DEBUGPL(DBG_ANY, "Backed up hprt0 = %08x\n",
-+ hr->hprt0_local);
-+ DWC_DEBUGPL(DBG_ANY, "Backed up hfir = %08x\n",
-+ hr->hfir_local);
-+
-+ return 0;
-+}
-+
-+int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
-+{
-+ struct dwc_otg_global_regs_backup *gr;
-+ int i;
-+
-+ gr = core_if->gr_backup;
-+ if (!gr) {
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
-+ gr->gnptxfsiz_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
-+ gr->hptxfsiz_local);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
-+ gr->gdfifocfg_local);
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
-+ gr->dtxfsiz_local[i]);
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
-+ (gr->gahbcfg_local));
-+ return 0;
-+}
-+
-+int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
-+{
-+ struct dwc_otg_dev_regs_backup *dr;
-+ int i;
-+
-+ dr = core_if->dr_backup;
-+
-+ if (!dr) {
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (!rem_wakeup) {
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
-+ dr->dctl);
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
-+
-+ for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
-+ }
-+
-+ return 0;
-+}
-+
-+int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
-+{
-+ struct dwc_otg_host_regs_backup *hr;
-+ int i;
-+ hr = core_if->hr_backup;
-+
-+ if (!hr) {
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
-+ //if (!reset)
-+ //{
-+ // DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
-+ //}
-+
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
-+ hr->haintmsk_local);
-+ for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
-+ DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
-+ hr->hcintmsk_local[i]);
-+ }
-+
-+ return 0;
-+}
-+
-+int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
-+{
-+ struct dwc_otg_global_regs_backup *gr;
-+
-+ gr = core_if->gr_backup;
-+
-+ /* Restore values for LPM and I2C */
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
-+#endif
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
-+
-+ return 0;
-+}
-+
-+int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
-+{
-+ struct dwc_otg_global_regs_backup *gr;
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ gahbcfg_data_t gahbcfg = {.d32 = 0 };
-+ gusbcfg_data_t gusbcfg = {.d32 = 0 };
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+
-+ /* Restore LPM and I2C registers */
-+ restore_lpm_i2c_regs(core_if);
-+
-+ /* Set PCGCCTL to 0 */
-+ DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
-+
-+ gr = core_if->gr_backup;
-+ /* Load restore values for [31:14] bits */
-+ DWC_WRITE_REG32(core_if->pcgcctl,
-+ ((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
-+
-+ /* Umnask global Interrupt in GAHBCFG and restore it */
-+ gahbcfg.d32 = gr->gahbcfg_local;
-+ gahbcfg.b.glblintrmsk = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
-+
-+ /* Clear all pending interupts */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* Unmask restore done interrupt */
-+ gintmsk.b.restoredone = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
-+
-+ /* Restore GUSBCFG and HCFG/DCFG */
-+ gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
-+
-+ if (is_host) {
-+ hcfg_data_t hcfg = {.d32 = 0 };
-+ hcfg.d32 = core_if->hr_backup->hcfg_local;
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
-+ hcfg.d32);
-+
-+ /* Load restore values for [31:14] bits */
-+ pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
-+ pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
-+
-+ if (rmode)
-+ pcgcctl.b.restoremode = 1;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+ dwc_udelay(10);
-+
-+ /* Load restore values for [31:14] bits and set EssRegRestored bit */
-+ pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
-+ pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
-+ pcgcctl.b.ess_reg_restored = 1;
-+ if (rmode)
-+ pcgcctl.b.restoremode = 1;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+ } else {
-+ dcfg_data_t dcfg = {.d32 = 0 };
-+ dcfg.d32 = core_if->dr_backup->dcfg;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
-+
-+ /* Load restore values for [31:14] bits */
-+ pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
-+ pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
-+ if (!rmode) {
-+ pcgcctl.d32 |= 0x208;
-+ }
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+ dwc_udelay(10);
-+
-+ /* Load restore values for [31:14] bits */
-+ pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
-+ pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
-+ pcgcctl.b.ess_reg_restored = 1;
-+ if (!rmode)
-+ pcgcctl.d32 |= 0x208;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
-+ * type.
-+ */
-+static void init_fslspclksel(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t val;
-+ hcfg_data_t hcfg;
-+
-+ if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
-+ (core_if->hwcfg2.b.fs_phy_type == 1) &&
-+ (core_if->core_params->ulpi_fs_ls)) ||
-+ (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
-+ /* Full speed PHY */
-+ val = DWC_HCFG_48_MHZ;
-+ } else {
-+ /* High speed PHY running at full speed or high speed */
-+ val = DWC_HCFG_30_60_MHZ;
-+ }
-+
-+ DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
-+ hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
-+ hcfg.b.fslspclksel = val;
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
-+}
-+
-+/**
-+ * Initializes the DevSpd field of the DCFG register depending on the PHY type
-+ * and the enumeration speed of the device.
-+ */
-+static void init_devspd(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t val;
-+ dcfg_data_t dcfg;
-+
-+ if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
-+ (core_if->hwcfg2.b.fs_phy_type == 1) &&
-+ (core_if->core_params->ulpi_fs_ls)) ||
-+ (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
-+ /* Full speed PHY */
-+ val = 0x3;
-+ } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
-+ /* High speed PHY running at full speed */
-+ val = 0x1;
-+ } else {
-+ /* High speed PHY running at high speed */
-+ val = 0x0;
-+ }
-+
-+ DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
-+
-+ dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ dcfg.b.devspd = val;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
-+}
-+
-+/**
-+ * This function calculates the number of IN EPS
-+ * using GHWCFG1 and GHWCFG2 registers values
-+ *
-+ * @param core_if Programming view of the DWC_otg controller
-+ */
-+static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t num_in_eps = 0;
-+ uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
-+ uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
-+ uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
-+ int i;
-+
-+ for (i = 0; i < num_eps; ++i) {
-+ if (!(hwcfg1 & 0x1))
-+ num_in_eps++;
-+
-+ hwcfg1 >>= 2;
-+ }
-+
-+ if (core_if->hwcfg4.b.ded_fifo_en) {
-+ num_in_eps =
-+ (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
-+ }
-+
-+ return num_in_eps;
-+}
-+
-+/**
-+ * This function calculates the number of OUT EPS
-+ * using GHWCFG1 and GHWCFG2 registers values
-+ *
-+ * @param core_if Programming view of the DWC_otg controller
-+ */
-+static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t num_out_eps = 0;
-+ uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
-+ uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
-+ int i;
-+
-+ for (i = 0; i < num_eps; ++i) {
-+ if (!(hwcfg1 & 0x1))
-+ num_out_eps++;
-+
-+ hwcfg1 >>= 2;
-+ }
-+ return num_out_eps;
-+}
-+
-+/**
-+ * This function initializes the DWC_otg controller registers and
-+ * prepares the core for device mode or host mode operation.
-+ *
-+ * @param core_if Programming view of the DWC_otg controller
-+ *
-+ */
-+void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
-+{
-+ int i = 0;
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ gahbcfg_data_t ahbcfg = {.d32 = 0 };
-+ gusbcfg_data_t usbcfg = {.d32 = 0 };
-+ gi2cctl_data_t i2cctl = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
-+ core_if, global_regs);
-+
-+ /* Common Initialization */
-+ usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+
-+ /* Program the ULPI External VBUS bit if needed */
-+ usbcfg.b.ulpi_ext_vbus_drv =
-+ (core_if->core_params->phy_ulpi_ext_vbus ==
-+ DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
-+
-+ /* Set external TS Dline pulsing */
-+ usbcfg.b.term_sel_dl_pulse =
-+ (core_if->core_params->ts_dline == 1) ? 1 : 0;
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+
-+ /* Reset the Controller */
-+ dwc_otg_core_reset(core_if);
-+
-+ core_if->adp_enable = core_if->core_params->adp_supp_enable;
-+ core_if->power_down = core_if->core_params->power_down;
-+ core_if->otg_sts = 0;
-+
-+ /* Initialize parameters from Hardware configuration registers. */
-+ dev_if->num_in_eps = calc_num_in_eps(core_if);
-+ dev_if->num_out_eps = calc_num_out_eps(core_if);
-+
-+ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
-+ core_if->hwcfg4.b.num_dev_perio_in_ep);
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
-+ dev_if->perio_tx_fifo_size[i] =
-+ DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
-+ DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
-+ i, dev_if->perio_tx_fifo_size[i]);
-+ }
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+ dev_if->tx_fifo_size[i] =
-+ DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
-+ DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
-+ i, dev_if->tx_fifo_size[i]);
-+ }
-+
-+ core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
-+ core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
-+ core_if->nperio_tx_fifo_size =
-+ DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
-+
-+ DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
-+ core_if->nperio_tx_fifo_size);
-+
-+ /* This programming sequence needs to happen in FS mode before any other
-+ * programming occurs */
-+ if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
-+ (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
-+ /* If FS mode with FS PHY */
-+
-+ /* core_init() is now called on every switch so only call the
-+ * following for the first time through. */
-+ if (!core_if->phy_init_done) {
-+ core_if->phy_init_done = 1;
-+ DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
-+ usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+ usbcfg.b.physel = 1;
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+
-+ /* Reset after a PHY select */
-+ dwc_otg_core_reset(core_if);
-+ }
-+
-+ /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
-+ * do this on HNP Dev/Host mode switches (done in dev_init and
-+ * host_init). */
-+ if (dwc_otg_is_host_mode(core_if)) {
-+ init_fslspclksel(core_if);
-+ } else {
-+ init_devspd(core_if);
-+ }
-+
-+ if (core_if->core_params->i2c_enable) {
-+ DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
-+ /* Program GUSBCFG.OtgUtmifsSel to I2C */
-+ usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+ usbcfg.b.otgutmifssel = 1;
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+
-+ /* Program GI2CCTL.I2CEn */
-+ i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
-+ i2cctl.b.i2cdevaddr = 1;
-+ i2cctl.b.i2cen = 0;
-+ DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
-+ i2cctl.b.i2cen = 1;
-+ DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
-+ }
-+
-+ } /* endif speed == DWC_SPEED_PARAM_FULL */
-+ else {
-+ /* High speed PHY. */
-+ if (!core_if->phy_init_done) {
-+ core_if->phy_init_done = 1;
-+ /* HS PHY parameters. These parameters are preserved
-+ * during soft reset so only program the first time. Do
-+ * a soft reset immediately after setting phyif. */
-+
-+ if (core_if->core_params->phy_type == 2) {
-+ /* ULPI interface */
-+ usbcfg.b.ulpi_utmi_sel = 1;
-+ usbcfg.b.phyif = 0;
-+ usbcfg.b.ddrsel =
-+ core_if->core_params->phy_ulpi_ddr;
-+ } else if (core_if->core_params->phy_type == 1) {
-+ /* UTMI+ interface */
-+ usbcfg.b.ulpi_utmi_sel = 0;
-+ if (core_if->core_params->phy_utmi_width == 16) {
-+ usbcfg.b.phyif = 1;
-+
-+ } else {
-+ usbcfg.b.phyif = 0;
-+ }
-+ } else {
-+ DWC_ERROR("FS PHY TYPE\n");
-+ }
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+ /* Reset after setting the PHY parameters */
-+ dwc_otg_core_reset(core_if);
-+ }
-+ }
-+
-+ if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
-+ (core_if->hwcfg2.b.fs_phy_type == 1) &&
-+ (core_if->core_params->ulpi_fs_ls)) {
-+ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
-+ usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+ usbcfg.b.ulpi_fsls = 1;
-+ usbcfg.b.ulpi_clk_sus_m = 1;
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+ } else {
-+ usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+ usbcfg.b.ulpi_fsls = 0;
-+ usbcfg.b.ulpi_clk_sus_m = 0;
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+ }
-+
-+ /* Program the GAHBCFG Register. */
-+ switch (core_if->hwcfg2.b.architecture) {
-+
-+ case DWC_SLAVE_ONLY_ARCH:
-+ DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
-+ ahbcfg.b.nptxfemplvl_txfemplvl =
-+ DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
-+ ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
-+ core_if->dma_enable = 0;
-+ core_if->dma_desc_enable = 0;
-+ break;
-+
-+ case DWC_EXT_DMA_ARCH:
-+ DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
-+ {
-+ uint8_t brst_sz = core_if->core_params->dma_burst_size;
-+ ahbcfg.b.hburstlen = 0;
-+ while (brst_sz > 1) {
-+ ahbcfg.b.hburstlen++;
-+ brst_sz >>= 1;
-+ }
-+ }
-+ core_if->dma_enable = (core_if->core_params->dma_enable != 0);
-+ core_if->dma_desc_enable =
-+ (core_if->core_params->dma_desc_enable != 0);
-+ break;
-+
-+ case DWC_INT_DMA_ARCH:
-+ DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
-+ /* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
-+ Host mode ISOC in issue fix - vahrama */
-+ /* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
-+ ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
-+ core_if->dma_enable = (core_if->core_params->dma_enable != 0);
-+ core_if->dma_desc_enable =
-+ (core_if->core_params->dma_desc_enable != 0);
-+ break;
-+
-+ }
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable) {
-+ DWC_PRINTF("Using Descriptor DMA mode\n");
-+ } else {
-+ DWC_PRINTF("Using Buffer DMA mode\n");
-+
-+ }
-+ } else {
-+ DWC_PRINTF("Using Slave mode\n");
-+ core_if->dma_desc_enable = 0;
-+ }
-+
-+ if (core_if->core_params->ahb_single) {
-+ ahbcfg.b.ahbsingle = 1;
-+ }
-+
-+ ahbcfg.b.dmaenable = core_if->dma_enable;
-+ DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
-+
-+ core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
-+
-+ core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
-+ core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
-+ DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
-+ ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
-+ DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
-+ ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
-+
-+ /*
-+ * Program the GUSBCFG register.
-+ */
-+ usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+
-+ switch (core_if->hwcfg2.b.op_mode) {
-+ case DWC_MODE_HNP_SRP_CAPABLE:
-+ usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
-+ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
-+ usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
-+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
-+ break;
-+
-+ case DWC_MODE_SRP_ONLY_CAPABLE:
-+ usbcfg.b.hnpcap = 0;
-+ usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
-+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
-+ break;
-+
-+ case DWC_MODE_NO_HNP_SRP_CAPABLE:
-+ usbcfg.b.hnpcap = 0;
-+ usbcfg.b.srpcap = 0;
-+ break;
-+
-+ case DWC_MODE_SRP_CAPABLE_DEVICE:
-+ usbcfg.b.hnpcap = 0;
-+ usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
-+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
-+ break;
-+
-+ case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
-+ usbcfg.b.hnpcap = 0;
-+ usbcfg.b.srpcap = 0;
-+ break;
-+
-+ case DWC_MODE_SRP_CAPABLE_HOST:
-+ usbcfg.b.hnpcap = 0;
-+ usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
-+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
-+ break;
-+
-+ case DWC_MODE_NO_SRP_CAPABLE_HOST:
-+ usbcfg.b.hnpcap = 0;
-+ usbcfg.b.srpcap = 0;
-+ break;
-+ }
-+
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ if (core_if->core_params->lpm_enable) {
-+ glpmcfg_data_t lpmcfg = {.d32 = 0 };
-+
-+ /* To enable LPM support set lpm_cap_en bit */
-+ lpmcfg.b.lpm_cap_en = 1;
-+
-+ /* Make AppL1Res ACK */
-+ lpmcfg.b.appl_resp = 1;
-+
-+ /* Retry 3 times */
-+ lpmcfg.b.retry_count = 3;
-+
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
-+ 0, lpmcfg.d32);
-+
-+ }
-+#endif
-+ if (core_if->core_params->ic_usb_cap) {
-+ gusbcfg_data_t gusbcfg = {.d32 = 0 };
-+ gusbcfg.b.ic_usb_cap = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
-+ 0, gusbcfg.d32);
-+ }
-+ {
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+ gotgctl.b.otgver = core_if->core_params->otg_ver;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
-+ gotgctl.d32);
-+ /* Set OTG version supported */
-+ core_if->otg_ver = core_if->core_params->otg_ver;
-+ DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
-+ core_if->core_params->otg_ver, core_if->otg_ver);
-+ }
-+
-+
-+ /* Enable common interrupts */
-+ dwc_otg_enable_common_interrupts(core_if);
-+
-+ /* Do device or host intialization based on mode during PCD
-+ * and HCD initialization */
-+ if (dwc_otg_is_host_mode(core_if)) {
-+ DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
-+ core_if->op_state = A_HOST;
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
-+ core_if->op_state = B_PERIPHERAL;
-+#ifdef DWC_DEVICE_ONLY
-+ dwc_otg_core_dev_init(core_if);
-+#endif
-+ }
-+}
-+
-+/**
-+ * This function enables the Device mode interrupts.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ */
-+void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+
-+ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
-+
-+ /* Disable all interrupts. */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, 0);
-+
-+ /* Clear any pending interrupts */
-+ DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* Enable the common interrupts */
-+ dwc_otg_enable_common_interrupts(core_if);
-+
-+ /* Enable interrupts */
-+ intr_mask.b.usbreset = 1;
-+ intr_mask.b.enumdone = 1;
-+ /* Disable Disconnect interrupt in Device mode */
-+ intr_mask.b.disconnect = 0;
-+
-+ if (!core_if->multiproc_int_enable) {
-+ intr_mask.b.inepintr = 1;
-+ intr_mask.b.outepintr = 1;
-+ }
-+
-+ intr_mask.b.erlysuspend = 1;
-+
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ intr_mask.b.epmismatch = 1;
-+ }
-+
-+ //intr_mask.b.incomplisoout = 1;
-+ intr_mask.b.incomplisoin = 1;
-+
-+/* Enable the ignore frame number for ISOC xfers - MAS */
-+/* Disable to support high bandwith ISOC transfers - manukz */
-+#if 0
-+#ifdef DWC_UTE_PER_IO
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable) {
-+ dctl_data_t dctl1 = {.d32 = 0 };
-+ dctl1.b.ifrmnum = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ dctl, 0, dctl1.d32);
-+ DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
-+ DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->dctl));
-+ }
-+ }
-+#endif
-+#endif
-+#ifdef DWC_EN_ISOC
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable == 0) {
-+ if (core_if->pti_enh_enable) {
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dctl.b.ifrmnum = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ dev_if->dev_global_regs->dctl,
-+ 0, dctl.d32);
-+ } else {
-+ intr_mask.b.incomplisoin = 1;
-+ intr_mask.b.incomplisoout = 1;
-+ }
-+ }
-+ } else {
-+ intr_mask.b.incomplisoin = 1;
-+ intr_mask.b.incomplisoout = 1;
-+ }
-+#endif /* DWC_EN_ISOC */
-+
-+ /** @todo NGS: Should this be a module parameter? */
-+#ifdef USE_PERIODIC_EP
-+ intr_mask.b.isooutdrop = 1;
-+ intr_mask.b.eopframe = 1;
-+ intr_mask.b.incomplisoin = 1;
-+ intr_mask.b.incomplisoout = 1;
-+#endif
-+
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
-+
-+ DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
-+ DWC_READ_REG32(&global_regs->gintmsk));
-+}
-+
-+/**
-+ * This function initializes the DWC_otg controller registers for
-+ * device mode.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ */
-+void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
-+{
-+ int i;
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ dwc_otg_core_params_t *params = core_if->core_params;
-+ dcfg_data_t dcfg = {.d32 = 0 };
-+ depctl_data_t diepctl = {.d32 = 0 };
-+ grstctl_t resetctl = {.d32 = 0 };
-+ uint32_t rx_fifo_size;
-+ fifosize_data_t nptxfifosize;
-+ fifosize_data_t txfifosize;
-+ dthrctl_data_t dthrctl;
-+ fifosize_data_t ptxfifosize;
-+ uint16_t rxfsiz, nptxfsiz;
-+ gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
-+ hwcfg3_data_t hwcfg3 = {.d32 = 0 };
-+
-+ /* Restart the Phy Clock */
-+ DWC_WRITE_REG32(core_if->pcgcctl, 0);
-+
-+ /* Device configuration register */
-+ init_devspd(core_if);
-+ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
-+ dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
-+ dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
-+ /* Enable Device OUT NAK in case of DDMA mode*/
-+ if (core_if->core_params->dev_out_nak) {
-+ dcfg.b.endevoutnak = 1;
-+ }
-+
-+ if (core_if->core_params->cont_on_bna) {
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dctl.b.encontonbna = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ }
-+
-+
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
-+
-+ /* Configure data FIFO sizes */
-+ if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
-+ DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
-+ core_if->total_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
-+ params->dev_rx_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
-+ params->dev_nperio_tx_fifo_size);
-+
-+ /* Rx FIFO */
-+ DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->grxfsiz));
-+
-+#ifdef DWC_UTE_CFI
-+ core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
-+ core_if->init_rxfsiz = params->dev_rx_fifo_size;
-+#endif
-+ rx_fifo_size = params->dev_rx_fifo_size;
-+ DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
-+
-+ DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->grxfsiz));
-+
-+ /** Set Periodic Tx FIFO Mask all bits 0 */
-+ core_if->p_tx_msk = 0;
-+
-+ /** Set Tx FIFO Mask all bits 0 */
-+ core_if->tx_msk = 0;
-+
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ /* Non-periodic Tx FIFO */
-+ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxfsiz));
-+
-+ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
-+ nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
-+
-+ DWC_WRITE_REG32(&global_regs->gnptxfsiz,
-+ nptxfifosize.d32);
-+
-+ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxfsiz));
-+
-+ /**@todo NGS: Fix Periodic FIFO Sizing! */
-+ /*
-+ * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
-+ * Indexes of the FIFO size module parameters in the
-+ * dev_perio_tx_fifo_size array and the FIFO size registers in
-+ * the dptxfsiz array run from 0 to 14.
-+ */
-+ /** @todo Finish debug of this */
-+ ptxfifosize.b.startaddr =
-+ nptxfifosize.b.startaddr + nptxfifosize.b.depth;
-+ for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
-+ ptxfifosize.b.depth =
-+ params->dev_perio_tx_fifo_size[i];
-+ DWC_DEBUGPL(DBG_CIL,
-+ "initial dtxfsiz[%d]=%08x\n", i,
-+ DWC_READ_REG32(&global_regs->dtxfsiz
-+ [i]));
-+ DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
-+ ptxfifosize.d32);
-+ DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
-+ i,
-+ DWC_READ_REG32(&global_regs->dtxfsiz
-+ [i]));
-+ ptxfifosize.b.startaddr += ptxfifosize.b.depth;
-+ }
-+ } else {
-+ /*
-+ * Tx FIFOs These FIFOs are numbered from 1 to 15.
-+ * Indexes of the FIFO size module parameters in the
-+ * dev_tx_fifo_size array and the FIFO size registers in
-+ * the dtxfsiz array run from 0 to 14.
-+ */
-+
-+ /* Non-periodic Tx FIFO */
-+ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxfsiz));
-+
-+#ifdef DWC_UTE_CFI
-+ core_if->pwron_gnptxfsiz =
-+ (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
-+ core_if->init_gnptxfsiz =
-+ params->dev_nperio_tx_fifo_size;
-+#endif
-+ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
-+ nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
-+
-+ DWC_WRITE_REG32(&global_regs->gnptxfsiz,
-+ nptxfifosize.d32);
-+
-+ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxfsiz));
-+
-+ txfifosize.b.startaddr =
-+ nptxfifosize.b.startaddr + nptxfifosize.b.depth;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
-+
-+ txfifosize.b.depth =
-+ params->dev_tx_fifo_size[i];
-+
-+ DWC_DEBUGPL(DBG_CIL,
-+ "initial dtxfsiz[%d]=%08x\n",
-+ i,
-+ DWC_READ_REG32(&global_regs->dtxfsiz
-+ [i]));
-+
-+#ifdef DWC_UTE_CFI
-+ core_if->pwron_txfsiz[i] =
-+ (DWC_READ_REG32
-+ (&global_regs->dtxfsiz[i]) >> 16);
-+ core_if->init_txfsiz[i] =
-+ params->dev_tx_fifo_size[i];
-+#endif
-+ DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
-+ txfifosize.d32);
-+
-+ DWC_DEBUGPL(DBG_CIL,
-+ "new dtxfsiz[%d]=%08x\n",
-+ i,
-+ DWC_READ_REG32(&global_regs->dtxfsiz
-+ [i]));
-+
-+ txfifosize.b.startaddr += txfifosize.b.depth;
-+ }
-+ if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
-+ /* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
-+ gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
-+ hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
-+ gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
-+ DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
-+ rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
-+ nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
-+ gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
-+ DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
-+ }
-+ }
-+
-+ /* Flush the FIFOs */
-+ dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
-+ dwc_otg_flush_rx_fifo(core_if);
-+
-+ /* Flush the Learning Queue. */
-+ resetctl.b.intknqflsh = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
-+
-+ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
-+ core_if->start_predict = 0;
-+ for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
-+ core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
-+ }
-+ core_if->nextep_seq[0] = 0;
-+ core_if->first_in_nextep_seq = 0;
-+ diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
-+ diepctl.b.nextep = 0;
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
-+
-+ /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
-+ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
-+ dcfg.b.epmscnt = 2;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
-+
-+ DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
-+ __func__, core_if->first_in_nextep_seq);
-+ for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
-+ }
-+ DWC_DEBUGPL(DBG_CILV,"\n");
-+ }
-+
-+ /* Clear all pending Device Interrupts */
-+ /** @todo - if the condition needed to be checked
-+ * or in any case all pending interrutps should be cleared?
-+ */
-+ if (core_if->multiproc_int_enable) {
-+ for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
-+ DWC_WRITE_REG32(&dev_if->
-+ dev_global_regs->diepeachintmsk[i], 0);
-+ }
-+ }
-+
-+ for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
-+ DWC_WRITE_REG32(&dev_if->
-+ dev_global_regs->doepeachintmsk[i], 0);
-+ }
-+
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
-+ } else {
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
-+ }
-+
-+ for (i = 0; i <= dev_if->num_in_eps; i++) {
-+ depctl_data_t depctl;
-+ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ if (depctl.b.epena) {
-+ depctl.d32 = 0;
-+ depctl.b.epdis = 1;
-+ depctl.b.snak = 1;
-+ } else {
-+ depctl.d32 = 0;
-+ }
-+
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
-+
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
-+ }
-+
-+ for (i = 0; i <= dev_if->num_out_eps; i++) {
-+ depctl_data_t depctl;
-+ depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
-+ if (depctl.b.epena) {
-+ dctl_data_t dctl = {.d32 = 0 };
-+ gintmsk_data_t gintsts = {.d32 = 0 };
-+ doepint_data_t doepint = {.d32 = 0 };
-+ dctl.b.sgoutnak = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ do {
-+ dwc_udelay(10);
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ } while (!gintsts.b.goutnakeff);
-+ gintsts.d32 = 0;
-+ gintsts.b.goutnakeff = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ depctl.d32 = 0;
-+ depctl.b.epdis = 1;
-+ depctl.b.snak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
-+ do {
-+ dwc_udelay(10);
-+ doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[i]->doepint);
-+ } while (!doepint.b.epdisabled);
-+
-+ doepint.b.epdisabled = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
-+
-+ dctl.d32 = 0;
-+ dctl.b.cgoutnak = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ } else {
-+ depctl.d32 = 0;
-+ }
-+
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
-+
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
-+ }
-+
-+ if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
-+ dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
-+ dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
-+ dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
-+
-+ dev_if->rx_thr_length = params->rx_thr_length;
-+ dev_if->tx_thr_length = params->tx_thr_length;
-+
-+ dev_if->setup_desc_index = 0;
-+
-+ dthrctl.d32 = 0;
-+ dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
-+ dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
-+ dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
-+ dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
-+ dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
-+ dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
-+
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
-+ dthrctl.d32);
-+
-+ DWC_DEBUGPL(DBG_CIL,
-+ "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
-+ dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
-+ dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
-+ dthrctl.b.rx_thr_len);
-+
-+ }
-+
-+ dwc_otg_enable_device_interrupts(core_if);
-+
-+ {
-+ diepmsk_data_t msk = {.d32 = 0 };
-+ msk.b.txfifoundrn = 1;
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->
-+ diepeachintmsk[0], msk.d32, msk.d32);
-+ } else {
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
-+ msk.d32, msk.d32);
-+ }
-+ }
-+
-+ if (core_if->multiproc_int_enable) {
-+ /* Set NAK on Babble */
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dctl.b.nakonbble = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ }
-+
-+ if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
-+ dctl.b.sftdiscon = 0;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
-+ }
-+}
-+
-+/**
-+ * This function enables the Host mode interrupts.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ */
-+void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
-+
-+ /* Disable all interrupts. */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, 0);
-+
-+ /* Clear any pending interrupts. */
-+ DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
-+
-+ /* Enable the common interrupts */
-+ dwc_otg_enable_common_interrupts(core_if);
-+
-+ /*
-+ * Enable host mode interrupts without disturbing common
-+ * interrupts.
-+ */
-+
-+ intr_mask.b.disconnect = 1;
-+ intr_mask.b.portintr = 1;
-+ intr_mask.b.hcintr = 1;
-+
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
-+}
-+
-+/**
-+ * This function disables the Host Mode interrupts.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ */
-+void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
-+
-+ /*
-+ * Disable host mode interrupts without disturbing common
-+ * interrupts.
-+ */
-+ intr_mask.b.sofintr = 1;
-+ intr_mask.b.portintr = 1;
-+ intr_mask.b.hcintr = 1;
-+ intr_mask.b.ptxfempty = 1;
-+ intr_mask.b.nptxfempty = 1;
-+
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
-+}
-+
-+/**
-+ * This function initializes the DWC_otg controller registers for
-+ * host mode.
-+ *
-+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
-+ * request queues. Host channels are reset to ensure that they are ready for
-+ * performing transfers.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ *
-+ */
-+void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ dwc_otg_host_if_t *host_if = core_if->host_if;
-+ dwc_otg_core_params_t *params = core_if->core_params;
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+ fifosize_data_t nptxfifosize;
-+ fifosize_data_t ptxfifosize;
-+ uint16_t rxfsiz, nptxfsiz, hptxfsiz;
-+ gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
-+ int i;
-+ hcchar_data_t hcchar;
-+ hcfg_data_t hcfg;
-+ hfir_data_t hfir;
-+ dwc_otg_hc_regs_t *hc_regs;
-+ int num_channels;
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
-+
-+ /* Restart the Phy Clock */
-+ DWC_WRITE_REG32(core_if->pcgcctl, 0);
-+
-+ /* Initialize Host Configuration Register */
-+ init_fslspclksel(core_if);
-+ if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
-+ hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
-+ hcfg.b.fslssupp = 1;
-+ DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
-+
-+ }
-+
-+ /* This bit allows dynamic reloading of the HFIR register
-+ * during runtime. This bit needs to be programmed during
-+ * initial configuration and its value must not be changed
-+ * during runtime.*/
-+ if (core_if->core_params->reload_ctl == 1) {
-+ hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
-+ hfir.b.hfirrldctrl = 1;
-+ DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
-+ }
-+
-+ if (core_if->core_params->dma_desc_enable) {
-+ uint8_t op_mode = core_if->hwcfg2.b.op_mode;
-+ if (!
-+ (core_if->hwcfg4.b.desc_dma
-+ && (core_if->snpsid >= OTG_CORE_REV_2_90a)
-+ && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
-+ || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
-+ || (op_mode ==
-+ DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
-+ || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
-+ || (op_mode ==
-+ DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
-+
-+ DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
-+ "Either core version is below 2.90a or "
-+ "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
-+ "To run the driver in Buffer DMA host mode set dma_desc_enable "
-+ "module parameter to 0.\n");
-+ return;
-+ }
-+ hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
-+ hcfg.b.descdma = 1;
-+ DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
-+ }
-+
-+ /* Configure data FIFO sizes */
-+ if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
-+ DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
-+ core_if->total_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
-+ params->host_rx_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
-+ params->host_nperio_tx_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
-+ params->host_perio_tx_fifo_size);
-+
-+ /* Rx FIFO */
-+ DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->grxfsiz));
-+ DWC_WRITE_REG32(&global_regs->grxfsiz,
-+ params->host_rx_fifo_size);
-+ DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->grxfsiz));
-+
-+ /* Non-periodic Tx FIFO */
-+ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxfsiz));
-+ nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
-+ nptxfifosize.b.startaddr = params->host_rx_fifo_size;
-+ DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
-+ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxfsiz));
-+
-+ /* Periodic Tx FIFO */
-+ DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->hptxfsiz));
-+ ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
-+ ptxfifosize.b.startaddr =
-+ nptxfifosize.b.startaddr + nptxfifosize.b.depth;
-+ DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
-+ DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
-+ DWC_READ_REG32(&global_regs->hptxfsiz));
-+
-+ if (core_if->en_multiple_tx_fifo
-+ && core_if->snpsid <= OTG_CORE_REV_2_94a) {
-+ /* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
-+ gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
-+ rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
-+ nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
-+ hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
-+ gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
-+ DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
-+ }
-+ }
-+
-+ /* TODO - check this */
-+ /* Clear Host Set HNP Enable in the OTG Control Register */
-+ gotgctl.b.hstsethnpen = 1;
-+ DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
-+ /* Make sure the FIFOs are flushed. */
-+ dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
-+ dwc_otg_flush_rx_fifo(core_if);
-+
-+ /* Clear Host Set HNP Enable in the OTG Control Register */
-+ gotgctl.b.hstsethnpen = 1;
-+ DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
-+
-+ if (!core_if->core_params->dma_desc_enable) {
-+ /* Flush out any leftover queued requests. */
-+ num_channels = core_if->core_params->host_channels;
-+
-+ for (i = 0; i < num_channels; i++) {
-+ hc_regs = core_if->host_if->hc_regs[i];
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.chen = 0;
-+ hcchar.b.chdis = 1;
-+ hcchar.b.epdir = 0;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+ }
-+
-+ /* Halt all channels to put them into a known state. */
-+ for (i = 0; i < num_channels; i++) {
-+ int count = 0;
-+ hc_regs = core_if->host_if->hc_regs[i];
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.chen = 1;
-+ hcchar.b.chdis = 1;
-+ hcchar.b.epdir = 0;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
-+ do {
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (++count > 1000) {
-+ DWC_ERROR
-+ ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
-+ __func__, i, hcchar.d32, &hc_regs->hcchar);
-+ break;
-+ }
-+ dwc_udelay(1);
-+ } while (hcchar.b.chen);
-+ }
-+ }
-+
-+ /* Turn on the vbus power. */
-+ DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
-+ if (core_if->op_state == A_HOST) {
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
-+ if (hprt0.b.prtpwr == 0) {
-+ hprt0.b.prtpwr = 1;
-+ DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
-+ }
-+ }
-+
-+ dwc_otg_enable_host_interrupts(core_if);
-+}
-+
-+/**
-+ * Prepares a host channel for transferring packets to/from a specific
-+ * endpoint. The HCCHARn register is set up with the characteristics specified
-+ * in _hc. Host channel interrupts that may need to be serviced while this
-+ * transfer is in progress are enabled.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ * @param hc Information needed to initialize the host channel
-+ */
-+void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ uint32_t intr_enable;
-+ hcintmsk_data_t hc_intr_mask;
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+ hcchar_data_t hcchar;
-+ hcsplt_data_t hcsplt;
-+
-+ uint8_t hc_num = hc->hc_num;
-+ dwc_otg_host_if_t *host_if = core_if->host_if;
-+ dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
-+
-+ /* Clear old interrupt conditions for this host channel. */
-+ hc_intr_mask.d32 = 0xFFFFFFFF;
-+ hc_intr_mask.b.reserved14_31 = 0;
-+ DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
-+
-+ /* Enable channel interrupts required for this transfer. */
-+ hc_intr_mask.d32 = 0;
-+ hc_intr_mask.b.chhltd = 1;
-+ if (core_if->dma_enable) {
-+ /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
-+ if (!core_if->dma_desc_enable)
-+ hc_intr_mask.b.ahberr = 1;
-+ else {
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
-+ hc_intr_mask.b.xfercompl = 1;
-+ }
-+
-+ if (hc->error_state && !hc->do_split &&
-+ hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
-+ hc_intr_mask.b.ack = 1;
-+ if (hc->ep_is_in) {
-+ hc_intr_mask.b.datatglerr = 1;
-+ if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
-+ hc_intr_mask.b.nak = 1;
-+ }
-+ }
-+ }
-+ } else {
-+ switch (hc->ep_type) {
-+ case DWC_OTG_EP_TYPE_CONTROL:
-+ case DWC_OTG_EP_TYPE_BULK:
-+ hc_intr_mask.b.xfercompl = 1;
-+ hc_intr_mask.b.stall = 1;
-+ hc_intr_mask.b.xacterr = 1;
-+ hc_intr_mask.b.datatglerr = 1;
-+ if (hc->ep_is_in) {
-+ hc_intr_mask.b.bblerr = 1;
-+ } else {
-+ hc_intr_mask.b.nak = 1;
-+ hc_intr_mask.b.nyet = 1;
-+ if (hc->do_ping) {
-+ hc_intr_mask.b.ack = 1;
-+ }
-+ }
-+
-+ if (hc->do_split) {
-+ hc_intr_mask.b.nak = 1;
-+ if (hc->complete_split) {
-+ hc_intr_mask.b.nyet = 1;
-+ } else {
-+ hc_intr_mask.b.ack = 1;
-+ }
-+ }
-+
-+ if (hc->error_state) {
-+ hc_intr_mask.b.ack = 1;
-+ }
-+ break;
-+ case DWC_OTG_EP_TYPE_INTR:
-+ hc_intr_mask.b.xfercompl = 1;
-+ hc_intr_mask.b.nak = 1;
-+ hc_intr_mask.b.stall = 1;
-+ hc_intr_mask.b.xacterr = 1;
-+ hc_intr_mask.b.datatglerr = 1;
-+ hc_intr_mask.b.frmovrun = 1;
-+
-+ if (hc->ep_is_in) {
-+ hc_intr_mask.b.bblerr = 1;
-+ }
-+ if (hc->error_state) {
-+ hc_intr_mask.b.ack = 1;
-+ }
-+ if (hc->do_split) {
-+ if (hc->complete_split) {
-+ hc_intr_mask.b.nyet = 1;
-+ } else {
-+ hc_intr_mask.b.ack = 1;
-+ }
-+ }
-+ break;
-+ case DWC_OTG_EP_TYPE_ISOC:
-+ hc_intr_mask.b.xfercompl = 1;
-+ hc_intr_mask.b.frmovrun = 1;
-+ hc_intr_mask.b.ack = 1;
-+
-+ if (hc->ep_is_in) {
-+ hc_intr_mask.b.xacterr = 1;
-+ hc_intr_mask.b.bblerr = 1;
-+ }
-+ break;
-+ }
-+ }
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
-+
-+ /* Enable the top level host channel interrupt. */
-+ intr_enable = (1 << hc_num);
-+ DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
-+
-+ /* Make sure host channel interrupts are enabled. */
-+ gintmsk.b.hcintr = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
-+
-+ /*
-+ * Program the HCCHARn register with the endpoint characteristics for
-+ * the current transfer.
-+ */
-+ hcchar.d32 = 0;
-+ hcchar.b.devaddr = hc->dev_addr;
-+ hcchar.b.epnum = hc->ep_num;
-+ hcchar.b.epdir = hc->ep_is_in;
-+ hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
-+ hcchar.b.eptype = hc->ep_type;
-+ hcchar.b.mps = hc->max_packet;
-+
-+ DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
-+ __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
-+ DWC_DEBUGPL(DBG_HCDV, " Is In %d, Is Low Speed %d, EP Type %d, "
-+ "Max Pkt %d, Multi Cnt %d\n",
-+ hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
-+ hcchar.b.mps, hcchar.b.multicnt);
-+
-+ /*
-+ * Program the HCSPLIT register for SPLITs
-+ */
-+ hcsplt.d32 = 0;
-+ if (hc->do_split) {
-+ DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
-+ hc->hc_num,
-+ hc->complete_split ? "CSPLIT" : "SSPLIT");
-+ hcsplt.b.compsplt = hc->complete_split;
-+ hcsplt.b.xactpos = hc->xact_pos;
-+ hcsplt.b.hubaddr = hc->hub_addr;
-+ hcsplt.b.prtaddr = hc->port_addr;
-+ DWC_DEBUGPL(DBG_HCDV, "\t comp split %d\n", hc->complete_split);
-+ DWC_DEBUGPL(DBG_HCDV, "\t xact pos %d\n", hc->xact_pos);
-+ DWC_DEBUGPL(DBG_HCDV, "\t hub addr %d\n", hc->hub_addr);
-+ DWC_DEBUGPL(DBG_HCDV, "\t port addr %d\n", hc->port_addr);
-+ DWC_DEBUGPL(DBG_HCDV, "\t is_in %d\n", hc->ep_is_in);
-+ DWC_DEBUGPL(DBG_HCDV, "\t Max Pkt: %d\n", hcchar.b.mps);
-+ DWC_DEBUGPL(DBG_HCDV, "\t xferlen: %d\n", hc->xfer_len);
-+ }
-+ DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
-+
-+}
-+
-+/**
-+ * Attempts to halt a host channel. This function should only be called in
-+ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
-+ * normal circumstances in DMA mode, the controller halts the channel when the
-+ * transfer is complete or a condition occurs that requires application
-+ * intervention.
-+ *
-+ * In slave mode, checks for a free request queue entry, then sets the Channel
-+ * Enable and Channel Disable bits of the Host Channel Characteristics
-+ * register of the specified channel to intiate the halt. If there is no free
-+ * request queue entry, sets only the Channel Disable bit of the HCCHARn
-+ * register to flush requests for this channel. In the latter case, sets a
-+ * flag to indicate that the host channel needs to be halted when a request
-+ * queue slot is open.
-+ *
-+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
-+ * HCCHARn register. The controller ensures there is space in the request
-+ * queue before submitting the halt request.
-+ *
-+ * Some time may elapse before the core flushes any posted requests for this
-+ * host channel and halts. The Channel Halted interrupt handler completes the
-+ * deactivation of the host channel.
-+ *
-+ * @param core_if Controller register interface.
-+ * @param hc Host channel to halt.
-+ * @param halt_status Reason for halting the channel.
-+ */
-+void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
-+ dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
-+{
-+ gnptxsts_data_t nptxsts;
-+ hptxsts_data_t hptxsts;
-+ hcchar_data_t hcchar;
-+ dwc_otg_hc_regs_t *hc_regs;
-+ dwc_otg_core_global_regs_t *global_regs;
-+ dwc_otg_host_global_regs_t *host_global_regs;
-+
-+ hc_regs = core_if->host_if->hc_regs[hc->hc_num];
-+ global_regs = core_if->core_global_regs;
-+ host_global_regs = core_if->host_if->host_global_regs;
-+
-+ DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
-+ "halt_status = %d\n", halt_status);
-+
-+ if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
-+ halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
-+ /*
-+ * Disable all channel interrupts except Ch Halted. The QTD
-+ * and QH state associated with this transfer has been cleared
-+ * (in the case of URB_DEQUEUE), so the channel needs to be
-+ * shut down carefully to prevent crashes.
-+ */
-+ hcintmsk_data_t hcintmsk;
-+ hcintmsk.d32 = 0;
-+ hcintmsk.b.chhltd = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
-+
-+ /*
-+ * Make sure no other interrupts besides halt are currently
-+ * pending. Handling another interrupt could cause a crash due
-+ * to the QTD and QH state.
-+ */
-+ DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
-+
-+ /*
-+ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
-+ * even if the channel was already halted for some other
-+ * reason.
-+ */
-+ hc->halt_status = halt_status;
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chen == 0) {
-+ /*
-+ * The channel is either already halted or it hasn't
-+ * started yet. In DMA mode, the transfer may halt if
-+ * it finishes normally or a condition occurs that
-+ * requires driver intervention. Don't want to halt
-+ * the channel again. In either Slave or DMA mode,
-+ * it's possible that the transfer has been assigned
-+ * to a channel, but not started yet when an URB is
-+ * dequeued. Don't want to halt a channel that hasn't
-+ * started yet.
-+ */
-+ return;
-+ }
-+ }
-+ if (hc->halt_pending) {
-+ /*
-+ * A halt has already been issued for this channel. This might
-+ * happen when a transfer is aborted by a higher level in
-+ * the stack.
-+ */
-+#ifdef DEBUG
-+ DWC_PRINTF
-+ ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
-+ __func__, hc->hc_num);
-+
-+#endif
-+ return;
-+ }
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* No need to set the bit in DDMA for disabling the channel */
-+ //TODO check it everywhere channel is disabled
-+ if (!core_if->core_params->dma_desc_enable)
-+ hcchar.b.chen = 1;
-+ hcchar.b.chdis = 1;
-+
-+ if (!core_if->dma_enable) {
-+ /* Check for space in the request queue to issue the halt. */
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
-+ nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
-+ if (nptxsts.b.nptxqspcavail == 0) {
-+ hcchar.b.chen = 0;
-+ }
-+ } else {
-+ hptxsts.d32 =
-+ DWC_READ_REG32(&host_global_regs->hptxsts);
-+ if ((hptxsts.b.ptxqspcavail == 0)
-+ || (core_if->queuing_high_bandwidth)) {
-+ hcchar.b.chen = 0;
-+ }
-+ }
-+ }
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+
-+ hc->halt_status = halt_status;
-+
-+ if (hcchar.b.chen) {
-+ hc->halt_pending = 1;
-+ hc->halt_on_queue = 0;
-+ } else {
-+ hc->halt_on_queue = 1;
-+ }
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
-+ DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
-+ DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending);
-+ DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue);
-+ DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status);
-+
-+ return;
-+}
-+
-+/**
-+ * Clears the transfer state for a host channel. This function is normally
-+ * called after a transfer is done and the host channel is being released.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param hc Identifies the host channel to clean up.
-+ */
-+void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ dwc_otg_hc_regs_t *hc_regs;
-+
-+ hc->xfer_started = 0;
-+
-+ /*
-+ * Clear channel interrupt enables and any unhandled channel interrupt
-+ * conditions.
-+ */
-+ hc_regs = core_if->host_if->hc_regs[hc->hc_num];
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
-+ DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
-+#ifdef DEBUG
-+ DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
-+#endif
-+}
-+
-+/**
-+ * Sets the channel property that indicates in which frame a periodic transfer
-+ * should occur. This is always set to the _next_ frame. This function has no
-+ * effect on non-periodic transfers.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param hc Identifies the host channel to set up and its properties.
-+ * @param hcchar Current value of the HCCHAR register for the specified host
-+ * channel.
-+ */
-+static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
-+ dwc_hc_t * hc, hcchar_data_t * hcchar)
-+{
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ hfnum_data_t hfnum;
-+ hfnum.d32 =
-+ DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
-+
-+ /* 1 if _next_ frame is odd, 0 if it's even */
-+ hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
-+#ifdef DEBUG
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
-+ && !hc->complete_split) {
-+ switch (hfnum.b.frnum & 0x7) {
-+ case 7:
-+ core_if->hfnum_7_samples++;
-+ core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
-+ break;
-+ case 0:
-+ core_if->hfnum_0_samples++;
-+ core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
-+ break;
-+ default:
-+ core_if->hfnum_other_samples++;
-+ core_if->hfnum_other_frrem_accum +=
-+ hfnum.b.frrem;
-+ break;
-+ }
-+ }
-+#endif
-+ }
-+}
-+
-+#ifdef DEBUG
-+void hc_xfer_timeout(void *ptr)
-+{
-+ hc_xfer_info_t *xfer_info = NULL;
-+ int hc_num = 0;
-+
-+ if (ptr)
-+ xfer_info = (hc_xfer_info_t *) ptr;
-+
-+ if (!xfer_info->hc) {
-+ DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
-+ return;
-+ }
-+
-+ hc_num = xfer_info->hc->hc_num;
-+ DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
-+ DWC_WARN(" start_hcchar_val 0x%08x\n",
-+ xfer_info->core_if->start_hcchar_val[hc_num]);
-+}
-+#endif
-+
-+void ep_xfer_timeout(void *ptr)
-+{
-+ ep_xfer_info_t *xfer_info = NULL;
-+ int ep_num = 0;
-+ dctl_data_t dctl = {.d32 = 0 };
-+ gintsts_data_t gintsts = {.d32 = 0 };
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+
-+ if (ptr)
-+ xfer_info = (ep_xfer_info_t *) ptr;
-+
-+ if (!xfer_info->ep) {
-+ DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
-+ return;
-+ }
-+
-+ ep_num = xfer_info->ep->num;
-+ DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
-+ /* Put the sate to 2 as it was time outed */
-+ xfer_info->state = 2;
-+
-+ dctl.d32 =
-+ DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
-+ gintsts.d32 =
-+ DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
-+ gintmsk.d32 =
-+ DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
-+
-+ if (!gintmsk.b.goutnakeff) {
-+ /* Unmask it */
-+ gintmsk.b.goutnakeff = 1;
-+ DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
-+ gintmsk.d32);
-+
-+ }
-+
-+ if (!gintsts.b.goutnakeff) {
-+ dctl.b.sgoutnak = 1;
-+ }
-+ DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
-+ dctl.d32);
-+
-+}
-+
-+void set_pid_isoc(dwc_hc_t * hc)
-+{
-+ /* Set up the initial PID for the transfer. */
-+ if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
-+ if (hc->ep_is_in) {
-+ if (hc->multi_count == 1) {
-+ hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
-+ } else if (hc->multi_count == 2) {
-+ hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
-+ } else {
-+ hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
-+ }
-+ } else {
-+ if (hc->multi_count == 1) {
-+ hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
-+ } else {
-+ hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
-+ }
-+ }
-+ } else {
-+ hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
-+ }
-+}
-+
-+/**
-+ * This function does the setup for a data transfer for a host channel and
-+ * starts the transfer. May be called in either Slave mode or DMA mode. In
-+ * Slave mode, the caller must ensure that there is sufficient space in the
-+ * request queue and Tx Data FIFO.
-+ *
-+ * For an OUT transfer in Slave mode, it loads a data packet into the
-+ * appropriate FIFO. If necessary, additional data packets will be loaded in
-+ * the Host ISR.
-+ *
-+ * For an IN transfer in Slave mode, a data packet is requested. The data
-+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
-+ * additional data packets are requested in the Host ISR.
-+ *
-+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
-+ * register along with a packet count of 1 and the channel is enabled. This
-+ * causes a single PING transaction to occur. Other fields in HCTSIZ are
-+ * simply set to 0 since no data transfer occurs in this case.
-+ *
-+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
-+ * all the information required to perform the subsequent data transfer. In
-+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
-+ * controller performs the entire PING protocol, then starts the data
-+ * transfer.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param hc Information needed to initialize the host channel. The xfer_len
-+ * value may be reduced to accommodate the max widths of the XferSize and
-+ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
-+ * to reflect the final xfer_len value.
-+ */
-+void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ hcchar_data_t hcchar;
-+ hctsiz_data_t hctsiz;
-+ uint16_t num_packets;
-+ uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
-+ uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
-+ dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
-+
-+ hctsiz.d32 = 0;
-+
-+ if (hc->do_ping) {
-+ if (!core_if->dma_enable) {
-+ dwc_otg_hc_do_ping(core_if, hc);
-+ hc->xfer_started = 1;
-+ return;
-+ } else {
-+ hctsiz.b.dopng = 1;
-+ }
-+ }
-+
-+ if (hc->do_split) {
-+ num_packets = 1;
-+
-+ if (hc->complete_split && !hc->ep_is_in) {
-+ /* For CSPLIT OUT Transfer, set the size to 0 so the
-+ * core doesn't expect any data written to the FIFO */
-+ hc->xfer_len = 0;
-+ } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
-+ hc->xfer_len = hc->max_packet;
-+ } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
-+ hc->xfer_len = 188;
-+ }
-+
-+ hctsiz.b.xfersize = hc->xfer_len;
-+ } else {
-+ /*
-+ * Ensure that the transfer length and packet count will fit
-+ * in the widths allocated for them in the HCTSIZn register.
-+ */
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ /*
-+ * Make sure the transfer size is no larger than one
-+ * (micro)frame's worth of data. (A check was done
-+ * when the periodic transfer was accepted to ensure
-+ * that a (micro)frame's worth of data can be
-+ * programmed into a channel.)
-+ */
-+ uint32_t max_periodic_len =
-+ hc->multi_count * hc->max_packet;
-+ if (hc->xfer_len > max_periodic_len) {
-+ hc->xfer_len = max_periodic_len;
-+ } else {
-+ }
-+ } else if (hc->xfer_len > max_hc_xfer_size) {
-+ /* Make sure that xfer_len is a multiple of max packet size. */
-+ hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
-+ }
-+
-+ if (hc->xfer_len > 0) {
-+ num_packets =
-+ (hc->xfer_len + hc->max_packet -
-+ 1) / hc->max_packet;
-+ if (num_packets > max_hc_pkt_count) {
-+ num_packets = max_hc_pkt_count;
-+ hc->xfer_len = num_packets * hc->max_packet;
-+ }
-+ } else {
-+ /* Need 1 packet for transfer length of 0. */
-+ num_packets = 1;
-+ }
-+
-+ if (hc->ep_is_in) {
-+ /* Always program an integral # of max packets for IN transfers. */
-+ hc->xfer_len = num_packets * hc->max_packet;
-+ }
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ /*
-+ * Make sure that the multi_count field matches the
-+ * actual transfer length.
-+ */
-+ hc->multi_count = num_packets;
-+ }
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
-+ set_pid_isoc(hc);
-+
-+ hctsiz.b.xfersize = hc->xfer_len;
-+ }
-+
-+ hc->start_pkt_count = num_packets;
-+ hctsiz.b.pktcnt = num_packets;
-+ hctsiz.b.pid = hc->data_pid_start;
-+ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
-+ DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
-+ DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
-+ DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
-+
-+ if (core_if->dma_enable) {
-+ dwc_dma_t dma_addr;
-+ if (hc->align_buff) {
-+ dma_addr = hc->align_buff;
-+ } else {
-+ dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
-+ }
-+ DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
-+ }
-+
-+ /* Start the split */
-+ if (hc->do_split) {
-+ hcsplt_data_t hcsplt;
-+ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
-+ hcsplt.b.spltena = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
-+ }
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.multicnt = hc->multi_count;
-+ hc_set_even_odd_frame(core_if, hc, &hcchar);
-+#ifdef DEBUG
-+ core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
-+ if (hcchar.b.chdis) {
-+ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
-+ __func__, hc->hc_num, hcchar.d32);
-+ }
-+#endif
-+
-+ /* Set host channel enable after all other setup is complete. */
-+ hcchar.b.chen = 1;
-+ hcchar.b.chdis = 0;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+
-+ hc->xfer_started = 1;
-+ hc->requests++;
-+
-+ if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
-+ /* Load OUT packet into the appropriate Tx FIFO. */
-+ dwc_otg_hc_write_packet(core_if, hc);
-+ }
-+#ifdef DEBUG
-+ if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
-+ DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
-+ hc->hc_num, core_if);//GRAYG
-+ core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
-+ core_if->hc_xfer_info[hc->hc_num].hc = hc;
-+
-+ /* Start a timer for this transfer. */
-+ DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
-+ }
-+#endif
-+}
-+
-+/**
-+ * This function does the setup for a data transfer for a host channel
-+ * and starts the transfer in Descriptor DMA mode.
-+ *
-+ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
-+ * Sets PID and NTD values. For periodic transfers
-+ * initializes SCHED_INFO field with micro-frame bitmap.
-+ *
-+ * Initializes HCDMA register with descriptor list address and CTD value
-+ * then starts the transfer via enabling the channel.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param hc Information needed to initialize the host channel.
-+ */
-+void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
-+ hcchar_data_t hcchar;
-+ hctsiz_data_t hctsiz;
-+ hcdma_data_t hcdma;
-+
-+ hctsiz.d32 = 0;
-+
-+ if (hc->do_ping)
-+ hctsiz.b_ddma.dopng = 1;
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
-+ set_pid_isoc(hc);
-+
-+ /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
-+ hctsiz.b_ddma.pid = hc->data_pid_start;
-+ hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
-+ hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
-+ DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
-+ DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd);
-+
-+ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
-+
-+ hcdma.d32 = 0;
-+ hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
-+
-+ /* Always start from first descriptor. */
-+ hcdma.b.ctd = 0;
-+ DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.multicnt = hc->multi_count;
-+
-+#ifdef DEBUG
-+ core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
-+ if (hcchar.b.chdis) {
-+ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
-+ __func__, hc->hc_num, hcchar.d32);
-+ }
-+#endif
-+
-+ /* Set host channel enable after all other setup is complete. */
-+ hcchar.b.chen = 1;
-+ hcchar.b.chdis = 0;
-+
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+
-+ hc->xfer_started = 1;
-+ hc->requests++;
-+
-+#ifdef DEBUG
-+ if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
-+ && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
-+ DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
-+ hc->hc_num, core_if);//GRAYG
-+ core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
-+ core_if->hc_xfer_info[hc->hc_num].hc = hc;
-+ /* Start a timer for this transfer. */
-+ DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
-+ }
-+#endif
-+
-+}
-+
-+/**
-+ * This function continues a data transfer that was started by previous call
-+ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
-+ * sufficient space in the request queue and Tx Data FIFO. This function
-+ * should only be called in Slave mode. In DMA mode, the controller acts
-+ * autonomously to complete transfers programmed to a host channel.
-+ *
-+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
-+ * if there is any data remaining to be queued. For an IN transfer, another
-+ * data packet is always requested. For the SETUP phase of a control transfer,
-+ * this function does nothing.
-+ *
-+ * @return 1 if a new request is queued, 0 if no more requests are required
-+ * for this transfer.
-+ */
-+int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
-+
-+ if (hc->do_split) {
-+ /* SPLITs always queue just once per channel */
-+ return 0;
-+ } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
-+ /* SETUPs are queued only once since they can't be NAKed. */
-+ return 0;
-+ } else if (hc->ep_is_in) {
-+ /*
-+ * Always queue another request for other IN transfers. If
-+ * back-to-back INs are issued and NAKs are received for both,
-+ * the driver may still be processing the first NAK when the
-+ * second NAK is received. When the interrupt handler clears
-+ * the NAK interrupt for the first NAK, the second NAK will
-+ * not be seen. So we can't depend on the NAK interrupt
-+ * handler to requeue a NAKed request. Instead, IN requests
-+ * are issued each time this function is called. When the
-+ * transfer completes, the extra requests for the channel will
-+ * be flushed.
-+ */
-+ hcchar_data_t hcchar;
-+ dwc_otg_hc_regs_t *hc_regs =
-+ core_if->host_if->hc_regs[hc->hc_num];
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hc_set_even_odd_frame(core_if, hc, &hcchar);
-+ hcchar.b.chen = 1;
-+ hcchar.b.chdis = 0;
-+ DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n",
-+ hcchar.d32);
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+ hc->requests++;
-+ return 1;
-+ } else {
-+ /* OUT transfers. */
-+ if (hc->xfer_count < hc->xfer_len) {
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ hcchar_data_t hcchar;
-+ dwc_otg_hc_regs_t *hc_regs;
-+ hc_regs = core_if->host_if->hc_regs[hc->hc_num];
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hc_set_even_odd_frame(core_if, hc, &hcchar);
-+ }
-+
-+ /* Load OUT packet into the appropriate Tx FIFO. */
-+ dwc_otg_hc_write_packet(core_if, hc);
-+ hc->requests++;
-+ return 1;
-+ } else {
-+ return 0;
-+ }
-+ }
-+}
-+
-+/**
-+ * Starts a PING transfer. This function should only be called in Slave mode.
-+ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
-+ */
-+void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ hcchar_data_t hcchar;
-+ hctsiz_data_t hctsiz;
-+ dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
-+
-+ hctsiz.d32 = 0;
-+ hctsiz.b.dopng = 1;
-+ hctsiz.b.pktcnt = 1;
-+ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.chen = 1;
-+ hcchar.b.chdis = 0;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+}
-+
-+/*
-+ * This function writes a packet into the Tx FIFO associated with the Host
-+ * Channel. For a channel associated with a non-periodic EP, the non-periodic
-+ * Tx FIFO is written. For a channel associated with a periodic EP, the
-+ * periodic Tx FIFO is written. This function should only be called in Slave
-+ * mode.
-+ *
-+ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
-+ * then number of bytes written to the Tx FIFO.
-+ */
-+void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
-+{
-+ uint32_t i;
-+ uint32_t remaining_count;
-+ uint32_t byte_count;
-+ uint32_t dword_count;
-+
-+ uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
-+ uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
-+
-+ remaining_count = hc->xfer_len - hc->xfer_count;
-+ if (remaining_count > hc->max_packet) {
-+ byte_count = hc->max_packet;
-+ } else {
-+ byte_count = remaining_count;
-+ }
-+
-+ dword_count = (byte_count + 3) / 4;
-+
-+ if ((((unsigned long)data_buff) & 0x3) == 0) {
-+ /* xfer_buff is DWORD aligned. */
-+ for (i = 0; i < dword_count; i++, data_buff++) {
-+ DWC_WRITE_REG32(data_fifo, *data_buff);
-+ }
-+ } else {
-+ /* xfer_buff is not DWORD aligned. */
-+ for (i = 0; i < dword_count; i++, data_buff++) {
-+ uint32_t data;
-+ data =
-+ (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
-+ 16 | data_buff[3] << 24);
-+ DWC_WRITE_REG32(data_fifo, data);
-+ }
-+ }
-+
-+ hc->xfer_count += byte_count;
-+ hc->xfer_buff += byte_count;
-+}
-+
-+/**
-+ * Gets the current USB frame number. This is the frame number from the last
-+ * SOF packet.
-+ */
-+uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
-+{
-+ dsts_data_t dsts;
-+ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+
-+ /* read current frame/microframe number from DSTS register */
-+ return dsts.b.soffn;
-+}
-+
-+/**
-+ * Calculates and gets the frame Interval value of HFIR register according PHY
-+ * type and speed.The application can modify a value of HFIR register only after
-+ * the Port Enable bit of the Host Port Control and Status register
-+ * (HPRT.PrtEnaPort) has been set.
-+*/
-+
-+uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
-+{
-+ gusbcfg_data_t usbcfg;
-+ hwcfg2_data_t hwcfg2;
-+ hprt0_data_t hprt0;
-+ int clock = 60; // default value
-+ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
-+ hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
-+ if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
-+ clock = 60;
-+ if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
-+ clock = 48;
-+ if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
-+ !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
-+ clock = 30;
-+ if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
-+ !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
-+ clock = 60;
-+ if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
-+ !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
-+ clock = 48;
-+ if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
-+ clock = 48;
-+ if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
-+ clock = 48;
-+ if (hprt0.b.prtspd == 0)
-+ /* High speed case */
-+ return 125 * clock;
-+ else
-+ /* FS/LS case */
-+ return 1000 * clock;
-+}
-+
-+/**
-+ * This function reads a setup packet from the Rx FIFO into the destination
-+ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
-+ * Interrupt routine when a SETUP packet has been received in Slave mode.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param dest Destination buffer for packet data.
-+ */
-+void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
-+{
-+ device_grxsts_data_t status;
-+ /* Get the 8 bytes of a setup transaction data */
-+
-+ /* Pop 2 DWORDS off the receive data FIFO into memory */
-+ dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
-+ dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ status.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
-+ DWC_DEBUGPL(DBG_ANY,
-+ "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
-+ status.b.epnum, status.b.bcnt, status.b.pktsts,
-+ status.b.fn, status.b.fn);
-+ }
-+}
-+
-+/**
-+ * This function enables EP0 OUT to receive SETUP packets and configures EP0
-+ * IN for transmitting packets. It is normally called when the
-+ * "Enumeration Done" interrupt occurs.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP0 data.
-+ */
-+void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ dsts_data_t dsts;
-+ depctl_data_t diepctl;
-+ depctl_data_t doepctl;
-+ dctl_data_t dctl = {.d32 = 0 };
-+
-+ ep->stp_rollover = 0;
-+ /* Read the Device Status and Endpoint 0 Control registers */
-+ dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
-+ diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
-+ doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
-+
-+ /* Set the MPS of the IN EP based on the enumeration speed */
-+ switch (dsts.b.enumspd) {
-+ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
-+ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
-+ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
-+ diepctl.b.mps = DWC_DEP0CTL_MPS_64;
-+ break;
-+ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
-+ diepctl.b.mps = DWC_DEP0CTL_MPS_8;
-+ break;
-+ }
-+
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
-+
-+ /* Enable OUT EP for receive */
-+ if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
-+ doepctl.b.epena = 1;
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
-+ }
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
-+ DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
-+ DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
-+ DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
-+#endif
-+ dctl.b.cgnpinnak = 1;
-+
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
-+ DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
-+ DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
-+
-+}
-+
-+/**
-+ * This function activates an EP. The Device EP control register for
-+ * the EP is configured as defined in the ep structure. Note: This
-+ * function is not used for EP0.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to activate.
-+ */
-+void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ depctl_data_t depctl;
-+ volatile uint32_t *addr;
-+ daint_data_t daintmsk = {.d32 = 0 };
-+ dcfg_data_t dcfg;
-+ uint8_t i;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
-+ (ep->is_in ? "IN" : "OUT"));
-+
-+#ifdef DWC_UTE_PER_IO
-+ ep->xiso_frame_num = 0xFFFFFFFF;
-+ ep->xiso_active_xfers = 0;
-+ ep->xiso_queued_xfers = 0;
-+#endif
-+ /* Read DEPCTLn register */
-+ if (ep->is_in == 1) {
-+ addr = &dev_if->in_ep_regs[ep->num]->diepctl;
-+ daintmsk.ep.in = 1 << ep->num;
-+ } else {
-+ addr = &dev_if->out_ep_regs[ep->num]->doepctl;
-+ daintmsk.ep.out = 1 << ep->num;
-+ }
-+
-+ /* If the EP is already active don't change the EP Control
-+ * register. */
-+ depctl.d32 = DWC_READ_REG32(addr);
-+ if (!depctl.b.usbactep) {
-+ depctl.b.mps = ep->maxpacket;
-+ depctl.b.eptype = ep->type;
-+ depctl.b.txfnum = ep->tx_fifo_num;
-+
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ depctl.b.setd0pid = 1; // ???
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ }
-+ depctl.b.usbactep = 1;
-+
-+ /* Update nextep_seq array and EPMSCNT in DCFG*/
-+ if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) { // NP IN EP
-+ for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
-+ if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
-+ break;
-+ }
-+ core_if->nextep_seq[i] = ep->num;
-+ core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
-+ depctl.b.nextep = core_if->nextep_seq[ep->num];
-+ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
-+ dcfg.b.epmscnt++;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
-+ __func__, core_if->first_in_nextep_seq);
-+ for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_DEBUGPL(DBG_PCDV, "%2d\n",
-+ core_if->nextep_seq[i]);
-+ }
-+
-+ }
-+
-+
-+ DWC_WRITE_REG32(addr, depctl.d32);
-+ DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
-+ }
-+
-+ /* Enable the Interrupt for this EP */
-+ if (core_if->multiproc_int_enable) {
-+ if (ep->is_in == 1) {
-+ diepmsk_data_t diepmsk = {.d32 = 0 };
-+ diepmsk.b.xfercompl = 1;
-+ diepmsk.b.timeout = 1;
-+ diepmsk.b.epdisabled = 1;
-+ diepmsk.b.ahberr = 1;
-+ diepmsk.b.intknepmis = 1;
-+ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
-+ diepmsk.b.intknepmis = 0;
-+ diepmsk.b.txfifoundrn = 1; //?????
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ diepmsk.b.nak = 1;
-+ }
-+
-+
-+
-+/*
-+ if (core_if->dma_desc_enable) {
-+ diepmsk.b.bna = 1;
-+ }
-+*/
-+/*
-+ if (core_if->dma_enable) {
-+ doepmsk.b.nak = 1;
-+ }
-+*/
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->
-+ diepeachintmsk[ep->num], diepmsk.d32);
-+
-+ } else {
-+ doepmsk_data_t doepmsk = {.d32 = 0 };
-+ doepmsk.b.xfercompl = 1;
-+ doepmsk.b.ahberr = 1;
-+ doepmsk.b.epdisabled = 1;
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC)
-+ doepmsk.b.outtknepdis = 1;
-+
-+/*
-+
-+ if (core_if->dma_desc_enable) {
-+ doepmsk.b.bna = 1;
-+ }
-+*/
-+/*
-+ doepmsk.b.babble = 1;
-+ doepmsk.b.nyet = 1;
-+ doepmsk.b.nak = 1;
-+*/
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->
-+ doepeachintmsk[ep->num], doepmsk.d32);
-+ }
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
-+ 0, daintmsk.d32);
-+ } else {
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ if (ep->is_in) {
-+ diepmsk_data_t diepmsk = {.d32 = 0 };
-+ diepmsk.b.nak = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
-+ } else {
-+ doepmsk_data_t doepmsk = {.d32 = 0 };
-+ doepmsk.b.outtknepdis = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
-+ }
-+ }
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
-+ 0, daintmsk.d32);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
-+ DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
-+
-+ ep->stall_clear_flag = 0;
-+
-+ return;
-+}
-+
-+/**
-+ * This function deactivates an EP. This is done by clearing the USB Active
-+ * EP bit in the Device EP control register. Note: This function is not used
-+ * for EP0. EP0 cannot be deactivated.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to deactivate.
-+ */
-+void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl = {.d32 = 0 };
-+ volatile uint32_t *addr;
-+ daint_data_t daintmsk = {.d32 = 0 };
-+ dcfg_data_t dcfg;
-+ uint8_t i = 0;
-+
-+#ifdef DWC_UTE_PER_IO
-+ ep->xiso_frame_num = 0xFFFFFFFF;
-+ ep->xiso_active_xfers = 0;
-+ ep->xiso_queued_xfers = 0;
-+#endif
-+
-+ /* Read DEPCTLn register */
-+ if (ep->is_in == 1) {
-+ addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
-+ daintmsk.ep.in = 1 << ep->num;
-+ } else {
-+ addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
-+ daintmsk.ep.out = 1 << ep->num;
-+ }
-+
-+ depctl.d32 = DWC_READ_REG32(addr);
-+
-+ depctl.b.usbactep = 0;
-+
-+ /* Update nextep_seq array and EPMSCNT in DCFG*/
-+ if (!(depctl.b.eptype & 1) && ep->is_in == 1) { // NP EP IN
-+ for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
-+ if (core_if->nextep_seq[i] == ep->num)
-+ break;
-+ }
-+ core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
-+ if (core_if->first_in_nextep_seq == ep->num)
-+ core_if->first_in_nextep_seq = i;
-+ core_if->nextep_seq[ep->num] = 0xff;
-+ depctl.b.nextep = 0;
-+ dcfg.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ dcfg.b.epmscnt--;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
-+ dcfg.d32);
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
-+ __func__, core_if->first_in_nextep_seq);
-+ for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
-+ }
-+ }
-+
-+ if (ep->is_in == 1)
-+ depctl.b.txfnum = 0;
-+
-+ if (core_if->dma_desc_enable)
-+ depctl.b.epdis = 1;
-+
-+ DWC_WRITE_REG32(addr, depctl.d32);
-+ depctl.d32 = DWC_READ_REG32(addr);
-+ if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
-+ && depctl.b.epena) {
-+ depctl_data_t depctl = {.d32 = 0};
-+ if (ep->is_in) {
-+ diepint_data_t diepint = {.d32 = 0};
-+
-+ depctl.b.snak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ diepctl, depctl.d32);
-+ do {
-+ dwc_udelay(10);
-+ diepint.d32 =
-+ DWC_READ_REG32(&core_if->
-+ dev_if->in_ep_regs[ep->num]->
-+ diepint);
-+ } while (!diepint.b.inepnakeff);
-+ diepint.b.inepnakeff = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ diepint, diepint.d32);
-+ depctl.d32 = 0;
-+ depctl.b.epdis = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ diepctl, depctl.d32);
-+ do {
-+ dwc_udelay(10);
-+ diepint.d32 =
-+ DWC_READ_REG32(&core_if->
-+ dev_if->in_ep_regs[ep->num]->
-+ diepint);
-+ } while (!diepint.b.epdisabled);
-+ diepint.b.epdisabled = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ diepint, diepint.d32);
-+ } else {
-+ dctl_data_t dctl = {.d32 = 0};
-+ gintmsk_data_t gintsts = {.d32 = 0};
-+ doepint_data_t doepint = {.d32 = 0};
-+ dctl.b.sgoutnak = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ dctl, 0, dctl.d32);
-+ do {
-+ dwc_udelay(10);
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ } while (!gintsts.b.goutnakeff);
-+ gintsts.d32 = 0;
-+ gintsts.b.goutnakeff = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ depctl.d32 = 0;
-+ depctl.b.epdis = 1;
-+ depctl.b.snak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
-+ do
-+ {
-+ dwc_udelay(10);
-+ doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[ep->num]->doepint);
-+ } while (!doepint.b.epdisabled);
-+
-+ doepint.b.epdisabled = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
-+
-+ dctl.d32 = 0;
-+ dctl.b.cgoutnak = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ }
-+ }
-+
-+ /* Disable the Interrupt for this EP */
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
-+ daintmsk.d32, 0);
-+
-+ if (ep->is_in == 1) {
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
-+ diepeachintmsk[ep->num], 0);
-+ } else {
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
-+ doepeachintmsk[ep->num], 0);
-+ }
-+ } else {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
-+ daintmsk.d32, 0);
-+ }
-+
-+}
-+
-+/**
-+ * This function initializes dma descriptor chain.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ */
-+static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ uint32_t offset;
-+ uint32_t xfer_est;
-+ int i;
-+ unsigned maxxfer_local, total_len;
-+
-+ if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
-+ (ep->maxpacket%4)) {
-+ maxxfer_local = ep->maxpacket;
-+ total_len = ep->xfer_len;
-+ } else {
-+ maxxfer_local = ep->maxxfer;
-+ total_len = ep->total_len;
-+ }
-+
-+ ep->desc_cnt = (total_len / maxxfer_local) +
-+ ((total_len % maxxfer_local) ? 1 : 0);
-+
-+ if (!ep->desc_cnt)
-+ ep->desc_cnt = 1;
-+
-+ if (ep->desc_cnt > MAX_DMA_DESC_CNT)
-+ ep->desc_cnt = MAX_DMA_DESC_CNT;
-+
-+ dma_desc = ep->desc_addr;
-+ if (maxxfer_local == ep->maxpacket) {
-+ if ((total_len % maxxfer_local) &&
-+ (total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
-+ xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
-+ (total_len % maxxfer_local);
-+ } else
-+ xfer_est = ep->desc_cnt * maxxfer_local;
-+ } else
-+ xfer_est = total_len;
-+ offset = 0;
-+ for (i = 0; i < ep->desc_cnt; ++i) {
-+ /** DMA Descriptor Setup */
-+ if (xfer_est > maxxfer_local) {
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ dma_desc->status.b.l = 0;
-+ dma_desc->status.b.ioc = 0;
-+ dma_desc->status.b.sp = 0;
-+ dma_desc->status.b.bytes = maxxfer_local;
-+ dma_desc->buf = ep->dma_addr + offset;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+
-+ xfer_est -= maxxfer_local;
-+ offset += maxxfer_local;
-+ } else {
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ dma_desc->status.b.l = 1;
-+ dma_desc->status.b.ioc = 1;
-+ if (ep->is_in) {
-+ dma_desc->status.b.sp =
-+ (xfer_est %
-+ ep->maxpacket) ? 1 : ((ep->
-+ sent_zlp) ? 1 : 0);
-+ dma_desc->status.b.bytes = xfer_est;
-+ } else {
-+ if (maxxfer_local == ep->maxpacket)
-+ dma_desc->status.b.bytes = xfer_est;
-+ else
-+ dma_desc->status.b.bytes =
-+ xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
-+ }
-+
-+ dma_desc->buf = ep->dma_addr + offset;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+ }
-+ dma_desc++;
-+ }
-+}
-+/**
-+ * This function is called when to write ISOC data into appropriate dedicated
-+ * periodic FIFO.
-+ */
-+static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
-+{
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ dwc_otg_dev_in_ep_regs_t *ep_regs;
-+ dtxfsts_data_t txstatus = {.d32 = 0 };
-+ uint32_t len = 0;
-+ int epnum = dwc_ep->num;
-+ int dwords;
-+
-+ DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
-+
-+ ep_regs = core_if->dev_if->in_ep_regs[epnum];
-+
-+ len = dwc_ep->xfer_len - dwc_ep->xfer_count;
-+
-+ if (len > dwc_ep->maxpacket) {
-+ len = dwc_ep->maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+
-+ /* While there is space in the queue and space in the FIFO and
-+ * More data to tranfer, Write packets to the Tx FIFO */
-+ txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
-+ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
-+
-+ while (txstatus.b.txfspcavail > dwords &&
-+ dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
-+ /* Write the FIFO */
-+ dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
-+
-+ len = dwc_ep->xfer_len - dwc_ep->xfer_count;
-+ if (len > dwc_ep->maxpacket) {
-+ len = dwc_ep->maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+ txstatus.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
-+ DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
-+ txstatus.d32);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
-+ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
-+
-+ return 1;
-+}
-+/**
-+ * This function does the setup for a data transfer for an EP and
-+ * starts the transfer. For an IN transfer, the packets will be
-+ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
-+ * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ */
-+
-+void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl;
-+ deptsiz_data_t deptsiz;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
-+ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
-+ "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
-+ ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
-+ ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
-+ ep->total_len);
-+ /* IN endpoint */
-+ if (ep->is_in == 1) {
-+ dwc_otg_dev_in_ep_regs_t *in_regs =
-+ core_if->dev_if->in_ep_regs[ep->num];
-+
-+ gnptxsts_data_t gtxstatus;
-+
-+ gtxstatus.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
-+
-+ if (core_if->en_multiple_tx_fifo == 0
-+ && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
-+#ifdef DEBUG
-+ DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
-+#endif
-+ return;
-+ }
-+
-+ depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
-+ deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
-+
-+ if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
-+ ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
-+ ep->maxxfer : (ep->total_len - ep->xfer_len);
-+ else
-+ ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
-+ MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
-+
-+
-+ /* Zero Length Packet? */
-+ if ((ep->xfer_len - ep->xfer_count) == 0) {
-+ deptsiz.b.xfersize = 0;
-+ deptsiz.b.pktcnt = 1;
-+ } else {
-+ /* Program the transfer size and packet count
-+ * as follows: xfersize = N * maxpacket +
-+ * short_packet pktcnt = N + (short_packet
-+ * exist ? 1 : 0)
-+ */
-+ deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
-+ deptsiz.b.pktcnt =
-+ (ep->xfer_len - ep->xfer_count - 1 +
-+ ep->maxpacket) / ep->maxpacket;
-+ if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
-+ deptsiz.b.pktcnt = MAX_PKT_CNT;
-+ deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
-+ }
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC)
-+ deptsiz.b.mc = deptsiz.b.pktcnt;
-+ }
-+
-+ /* Write the DMA register */
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable == 0) {
-+ if (ep->type != DWC_OTG_EP_TYPE_ISOC)
-+ deptsiz.b.mc = 1;
-+ DWC_WRITE_REG32(&in_regs->dieptsiz,
-+ deptsiz.d32);
-+ DWC_WRITE_REG32(&(in_regs->diepdma),
-+ (uint32_t) ep->dma_addr);
-+ } else {
-+#ifdef DWC_UTE_CFI
-+ /* The descriptor chain should be already initialized by now */
-+ if (ep->buff_mode != BM_STANDARD) {
-+ DWC_WRITE_REG32(&in_regs->diepdma,
-+ ep->descs_dma_addr);
-+ } else {
-+#endif
-+ init_dma_desc_chain(core_if, ep);
-+ /** DIEPDMAn Register write */
-+ DWC_WRITE_REG32(&in_regs->diepdma,
-+ ep->dma_desc_addr);
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ }
-+ } else {
-+ DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
-+ if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
-+ /**
-+ * Enable the Non-Periodic Tx FIFO empty interrupt,
-+ * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
-+ * the data will be written into the fifo by the ISR.
-+ */
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32
-+ (&core_if->core_global_regs->gintmsk,
-+ intr_mask.d32, intr_mask.d32);
-+ } else {
-+ /* Enable the Tx FIFO Empty Interrupt for this EP */
-+ if (ep->xfer_len > 0) {
-+ uint32_t fifoemptymsk = 0;
-+ fifoemptymsk = 1 << ep->num;
-+ DWC_MODIFY_REG32
-+ (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
-+ 0, fifoemptymsk);
-+
-+ }
-+ }
-+ } else {
-+ write_isoc_tx_fifo(core_if, ep);
-+ }
-+ }
-+ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
-+ depctl.b.nextep = core_if->nextep_seq[ep->num];
-+
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ dsts_data_t dsts = {.d32 = 0};
-+ if (ep->bInterval == 1) {
-+ dsts.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->dsts);
-+ ep->frame_num = dsts.b.soffn + ep->bInterval;
-+ if (ep->frame_num > 0x3FFF) {
-+ ep->frm_overrun = 1;
-+ ep->frame_num &= 0x3FFF;
-+ } else
-+ ep->frm_overrun = 0;
-+ if (ep->frame_num & 0x1) {
-+ depctl.b.setd1pid = 1;
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ }
-+ }
-+ }
-+ /* EP enable, IN data in FIFO */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+ DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
-+
-+ } else {
-+ /* OUT endpoint */
-+ dwc_otg_dev_out_ep_regs_t *out_regs =
-+ core_if->dev_if->out_ep_regs[ep->num];
-+
-+ depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
-+ deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
-+
-+ if (!core_if->dma_desc_enable) {
-+ if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
-+ ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
-+ ep->maxxfer : (ep->total_len - ep->xfer_len);
-+ else
-+ ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
-+ - ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
-+ }
-+
-+ /* Program the transfer size and packet count as follows:
-+ *
-+ * pktcnt = N
-+ * xfersize = N * maxpacket
-+ */
-+ if ((ep->xfer_len - ep->xfer_count) == 0) {
-+ /* Zero Length Packet */
-+ deptsiz.b.xfersize = ep->maxpacket;
-+ deptsiz.b.pktcnt = 1;
-+ } else {
-+ deptsiz.b.pktcnt =
-+ (ep->xfer_len - ep->xfer_count +
-+ (ep->maxpacket - 1)) / ep->maxpacket;
-+ if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
-+ deptsiz.b.pktcnt = MAX_PKT_CNT;
-+ }
-+ if (!core_if->dma_desc_enable) {
-+ ep->xfer_len =
-+ deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
-+ }
-+ deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
-+ ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+
-+ if (core_if->dma_enable) {
-+ if (!core_if->dma_desc_enable) {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz,
-+ deptsiz.d32);
-+
-+ DWC_WRITE_REG32(&(out_regs->doepdma),
-+ (uint32_t) ep->dma_addr);
-+ } else {
-+#ifdef DWC_UTE_CFI
-+ /* The descriptor chain should be already initialized by now */
-+ if (ep->buff_mode != BM_STANDARD) {
-+ DWC_WRITE_REG32(&out_regs->doepdma,
-+ ep->descs_dma_addr);
-+ } else {
-+#endif
-+ /** This is used for interrupt out transfers*/
-+ if (!ep->xfer_len)
-+ ep->xfer_len = ep->total_len;
-+ init_dma_desc_chain(core_if, ep);
-+
-+ if (core_if->core_params->dev_out_nak) {
-+ if (ep->type == DWC_OTG_EP_TYPE_BULK) {
-+ deptsiz.b.pktcnt = (ep->total_len +
-+ (ep->maxpacket - 1)) / ep->maxpacket;
-+ deptsiz.b.xfersize = ep->total_len;
-+ /* Remember initial value of doeptsiz */
-+ core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
-+ DWC_WRITE_REG32(&out_regs->doeptsiz,
-+ deptsiz.d32);
-+ }
-+ }
-+ /** DOEPDMAn Register write */
-+ DWC_WRITE_REG32(&out_regs->doepdma,
-+ ep->dma_desc_addr);
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ }
-+ } else {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
-+ }
-+
-+ if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ dsts_data_t dsts = {.d32 = 0};
-+ if (ep->bInterval == 1) {
-+ dsts.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->dsts);
-+ ep->frame_num = dsts.b.soffn + ep->bInterval;
-+ if (ep->frame_num > 0x3FFF) {
-+ ep->frm_overrun = 1;
-+ ep->frame_num &= 0x3FFF;
-+ } else
-+ ep->frm_overrun = 0;
-+
-+ if (ep->frame_num & 0x1) {
-+ depctl.b.setd1pid = 1;
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ }
-+ }
-+ }
-+
-+ /* EP enable */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+
-+ DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
-+
-+ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
-+ DWC_READ_REG32(&out_regs->doepctl),
-+ DWC_READ_REG32(&out_regs->doeptsiz));
-+ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
-+ daintmsk),
-+ DWC_READ_REG32(&core_if->core_global_regs->
-+ gintmsk));
-+
-+ /* Timer is scheduling only for out bulk transfers for
-+ * "Device DDMA OUT NAK Enhancement" feature to inform user
-+ * about received data payload in case of timeout
-+ */
-+ if (core_if->core_params->dev_out_nak) {
-+ if (ep->type == DWC_OTG_EP_TYPE_BULK) {
-+ core_if->ep_xfer_info[ep->num].core_if = core_if;
-+ core_if->ep_xfer_info[ep->num].ep = ep;
-+ core_if->ep_xfer_info[ep->num].state = 1;
-+
-+ /* Start a timer for this transfer. */
-+ DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
-+ }
-+ }
-+ }
-+}
-+
-+/**
-+ * This function setup a zero length transfer in Buffer DMA and
-+ * Slave modes for usb requests with zero field set
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ *
-+ */
-+void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+
-+ depctl_data_t depctl;
-+ deptsiz_data_t deptsiz;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
-+ DWC_PRINTF("zero length transfer is called\n");
-+
-+ /* IN endpoint */
-+ if (ep->is_in == 1) {
-+ dwc_otg_dev_in_ep_regs_t *in_regs =
-+ core_if->dev_if->in_ep_regs[ep->num];
-+
-+ depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
-+ deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
-+
-+ deptsiz.b.xfersize = 0;
-+ deptsiz.b.pktcnt = 1;
-+
-+ /* Write the DMA register */
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable == 0) {
-+ deptsiz.b.mc = 1;
-+ DWC_WRITE_REG32(&in_regs->dieptsiz,
-+ deptsiz.d32);
-+ DWC_WRITE_REG32(&(in_regs->diepdma),
-+ (uint32_t) ep->dma_addr);
-+ }
-+ } else {
-+ DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
-+ /**
-+ * Enable the Non-Periodic Tx FIFO empty interrupt,
-+ * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
-+ * the data will be written into the fifo by the ISR.
-+ */
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->gintmsk,
-+ intr_mask.d32, intr_mask.d32);
-+ } else {
-+ /* Enable the Tx FIFO Empty Interrupt for this EP */
-+ if (ep->xfer_len > 0) {
-+ uint32_t fifoemptymsk = 0;
-+ fifoemptymsk = 1 << ep->num;
-+ DWC_MODIFY_REG32(&core_if->
-+ dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
-+ 0, fifoemptymsk);
-+ }
-+ }
-+ }
-+
-+ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
-+ depctl.b.nextep = core_if->nextep_seq[ep->num];
-+ /* EP enable, IN data in FIFO */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+ DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
-+
-+ } else {
-+ /* OUT endpoint */
-+ dwc_otg_dev_out_ep_regs_t *out_regs =
-+ core_if->dev_if->out_ep_regs[ep->num];
-+
-+ depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
-+ deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
-+
-+ /* Zero Length Packet */
-+ deptsiz.b.xfersize = ep->maxpacket;
-+ deptsiz.b.pktcnt = 1;
-+
-+ if (core_if->dma_enable) {
-+ if (!core_if->dma_desc_enable) {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz,
-+ deptsiz.d32);
-+
-+ DWC_WRITE_REG32(&(out_regs->doepdma),
-+ (uint32_t) ep->dma_addr);
-+ }
-+ } else {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
-+ }
-+
-+ /* EP enable */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+
-+ DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
-+
-+ }
-+}
-+
-+/**
-+ * This function does the setup for a data transfer for EP0 and starts
-+ * the transfer. For an IN transfer, the packets will be loaded into
-+ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
-+ * unloaded from the Rx FIFO in the ISR.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP0 data.
-+ */
-+void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl;
-+ deptsiz0_data_t deptsiz;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+
-+ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
-+ "xfer_buff=%p start_xfer_buff=%p \n",
-+ ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
-+ ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
-+
-+ ep->total_len = ep->xfer_len;
-+
-+ /* IN endpoint */
-+ if (ep->is_in == 1) {
-+ dwc_otg_dev_in_ep_regs_t *in_regs =
-+ core_if->dev_if->in_ep_regs[0];
-+
-+ gnptxsts_data_t gtxstatus;
-+
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
-+ if (depctl.b.epena)
-+ return;
-+ }
-+
-+ gtxstatus.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
-+
-+ /* If dedicated FIFO every time flush fifo before enable ep*/
-+ if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
-+ dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
-+
-+ if (core_if->en_multiple_tx_fifo == 0
-+ && gtxstatus.b.nptxqspcavail == 0
-+ && !core_if->dma_enable) {
-+#ifdef DEBUG
-+ deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
-+ DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
-+ DWC_READ_REG32(&in_regs->diepctl));
-+ DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
-+ deptsiz.d32,
-+ deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+ DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
-+ gtxstatus.d32);
-+#endif
-+ return;
-+ }
-+
-+ depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
-+ deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
-+
-+ /* Zero Length Packet? */
-+ if (ep->xfer_len == 0) {
-+ deptsiz.b.xfersize = 0;
-+ deptsiz.b.pktcnt = 1;
-+ } else {
-+ /* Program the transfer size and packet count
-+ * as follows: xfersize = N * maxpacket +
-+ * short_packet pktcnt = N + (short_packet
-+ * exist ? 1 : 0)
-+ */
-+ if (ep->xfer_len > ep->maxpacket) {
-+ ep->xfer_len = ep->maxpacket;
-+ deptsiz.b.xfersize = ep->maxpacket;
-+ } else {
-+ deptsiz.b.xfersize = ep->xfer_len;
-+ }
-+ deptsiz.b.pktcnt = 1;
-+
-+ }
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
-+ ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
-+ deptsiz.d32);
-+
-+ /* Write the DMA register */
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable == 0) {
-+ DWC_WRITE_REG32(&in_regs->dieptsiz,
-+ deptsiz.d32);
-+
-+ DWC_WRITE_REG32(&(in_regs->diepdma),
-+ (uint32_t) ep->dma_addr);
-+ } else {
-+ dma_desc = core_if->dev_if->in_desc_addr;
-+
-+ /** DMA Descriptor Setup */
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ dma_desc->status.b.l = 1;
-+ dma_desc->status.b.ioc = 1;
-+ dma_desc->status.b.sp =
-+ (ep->xfer_len == ep->maxpacket) ? 0 : 1;
-+ dma_desc->status.b.bytes = ep->xfer_len;
-+ dma_desc->buf = ep->dma_addr;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+
-+ /** DIEPDMA0 Register write */
-+ DWC_WRITE_REG32(&in_regs->diepdma,
-+ core_if->
-+ dev_if->dma_in_desc_addr);
-+ }
-+ } else {
-+ DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
-+ }
-+
-+ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
-+ depctl.b.nextep = core_if->nextep_seq[ep->num];
-+ /* EP enable, IN data in FIFO */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+ DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
-+
-+ /**
-+ * Enable the Non-Periodic Tx FIFO empty interrupt, the
-+ * data will be written into the fifo by the ISR.
-+ */
-+ if (!core_if->dma_enable) {
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->gintmsk,
-+ intr_mask.d32, intr_mask.d32);
-+ } else {
-+ /* Enable the Tx FIFO Empty Interrupt for this EP */
-+ if (ep->xfer_len > 0) {
-+ uint32_t fifoemptymsk = 0;
-+ fifoemptymsk |= 1 << ep->num;
-+ DWC_MODIFY_REG32(&core_if->
-+ dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
-+ 0, fifoemptymsk);
-+ }
-+ }
-+ }
-+ } else {
-+ /* OUT endpoint */
-+ dwc_otg_dev_out_ep_regs_t *out_regs =
-+ core_if->dev_if->out_ep_regs[0];
-+
-+ depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
-+ deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
-+
-+ /* Program the transfer size and packet count as follows:
-+ * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
-+ * pktcnt = N */
-+ /* Zero Length Packet */
-+ deptsiz.b.xfersize = ep->maxpacket;
-+ deptsiz.b.pktcnt = 1;
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a)
-+ deptsiz.b.supcnt = 3;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
-+ ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+
-+ if (core_if->dma_enable) {
-+ if (!core_if->dma_desc_enable) {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz,
-+ deptsiz.d32);
-+
-+ DWC_WRITE_REG32(&(out_regs->doepdma),
-+ (uint32_t) ep->dma_addr);
-+ } else {
-+ dma_desc = core_if->dev_if->out_desc_addr;
-+
-+ /** DMA Descriptor Setup */
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ dma_desc->status.b.mtrf = 0;
-+ dma_desc->status.b.sr = 0;
-+ }
-+ dma_desc->status.b.l = 1;
-+ dma_desc->status.b.ioc = 1;
-+ dma_desc->status.b.bytes = ep->maxpacket;
-+ dma_desc->buf = ep->dma_addr;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+
-+ /** DOEPDMA0 Register write */
-+ DWC_WRITE_REG32(&out_regs->doepdma,
-+ core_if->dev_if->
-+ dma_out_desc_addr);
-+ }
-+ } else {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
-+ }
-+
-+ /* EP enable */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+ DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
-+ }
-+}
-+
-+/**
-+ * This function continues control IN transfers started by
-+ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
-+ * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
-+ * bit for the packet count.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP0 data.
-+ */
-+void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl;
-+ deptsiz0_data_t deptsiz;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+
-+ if (ep->is_in == 1) {
-+ dwc_otg_dev_in_ep_regs_t *in_regs =
-+ core_if->dev_if->in_ep_regs[0];
-+ gnptxsts_data_t tx_status = {.d32 = 0 };
-+
-+ tx_status.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
-+ /** @todo Should there be check for room in the Tx
-+ * Status Queue. If not remove the code above this comment. */
-+
-+ depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
-+ deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
-+
-+ /* Program the transfer size and packet count
-+ * as follows: xfersize = N * maxpacket +
-+ * short_packet pktcnt = N + (short_packet
-+ * exist ? 1 : 0)
-+ */
-+
-+ if (core_if->dma_desc_enable == 0) {
-+ deptsiz.b.xfersize =
-+ (ep->total_len - ep->xfer_count) >
-+ ep->maxpacket ? ep->maxpacket : (ep->total_len -
-+ ep->xfer_count);
-+ deptsiz.b.pktcnt = 1;
-+ if (core_if->dma_enable == 0) {
-+ ep->xfer_len += deptsiz.b.xfersize;
-+ } else {
-+ ep->xfer_len = deptsiz.b.xfersize;
-+ }
-+ DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
-+ } else {
-+ ep->xfer_len =
-+ (ep->total_len - ep->xfer_count) >
-+ ep->maxpacket ? ep->maxpacket : (ep->total_len -
-+ ep->xfer_count);
-+
-+ dma_desc = core_if->dev_if->in_desc_addr;
-+
-+ /** DMA Descriptor Setup */
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ dma_desc->status.b.l = 1;
-+ dma_desc->status.b.ioc = 1;
-+ dma_desc->status.b.sp =
-+ (ep->xfer_len == ep->maxpacket) ? 0 : 1;
-+ dma_desc->status.b.bytes = ep->xfer_len;
-+ dma_desc->buf = ep->dma_addr;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+
-+ /** DIEPDMA0 Register write */
-+ DWC_WRITE_REG32(&in_regs->diepdma,
-+ core_if->dev_if->dma_in_desc_addr);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
-+ ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
-+ deptsiz.d32);
-+
-+ /* Write the DMA register */
-+ if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
-+ if (core_if->dma_desc_enable == 0)
-+ DWC_WRITE_REG32(&(in_regs->diepdma),
-+ (uint32_t) ep->dma_addr);
-+ }
-+ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
-+ depctl.b.nextep = core_if->nextep_seq[ep->num];
-+ /* EP enable, IN data in FIFO */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+ DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
-+
-+ /**
-+ * Enable the Non-Periodic Tx FIFO empty interrupt, the
-+ * data will be written into the fifo by the ISR.
-+ */
-+ if (!core_if->dma_enable) {
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ /* First clear it from GINTSTS */
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->gintmsk,
-+ intr_mask.d32, intr_mask.d32);
-+
-+ } else {
-+ /* Enable the Tx FIFO Empty Interrupt for this EP */
-+ if (ep->xfer_len > 0) {
-+ uint32_t fifoemptymsk = 0;
-+ fifoemptymsk |= 1 << ep->num;
-+ DWC_MODIFY_REG32(&core_if->
-+ dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
-+ 0, fifoemptymsk);
-+ }
-+ }
-+ }
-+ } else {
-+ dwc_otg_dev_out_ep_regs_t *out_regs =
-+ core_if->dev_if->out_ep_regs[0];
-+
-+ depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
-+ deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
-+
-+ /* Program the transfer size and packet count
-+ * as follows: xfersize = N * maxpacket +
-+ * short_packet pktcnt = N + (short_packet
-+ * exist ? 1 : 0)
-+ */
-+ deptsiz.b.xfersize = ep->maxpacket;
-+ deptsiz.b.pktcnt = 1;
-+
-+ if (core_if->dma_desc_enable == 0) {
-+ DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
-+ } else {
-+ dma_desc = core_if->dev_if->out_desc_addr;
-+
-+ /** DMA Descriptor Setup */
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ dma_desc->status.b.l = 1;
-+ dma_desc->status.b.ioc = 1;
-+ dma_desc->status.b.bytes = ep->maxpacket;
-+ dma_desc->buf = ep->dma_addr;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+
-+ /** DOEPDMA0 Register write */
-+ DWC_WRITE_REG32(&out_regs->doepdma,
-+ core_if->dev_if->dma_out_desc_addr);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
-+ ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
-+ deptsiz.d32);
-+
-+ /* Write the DMA register */
-+ if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
-+ if (core_if->dma_desc_enable == 0)
-+ DWC_WRITE_REG32(&(out_regs->doepdma),
-+ (uint32_t) ep->dma_addr);
-+
-+ }
-+
-+ /* EP enable, IN data in FIFO */
-+ depctl.b.cnak = 1;
-+ depctl.b.epena = 1;
-+ DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
-+
-+ }
-+}
-+
-+#ifdef DEBUG
-+void dump_msg(const u8 * buf, unsigned int length)
-+{
-+ unsigned int start, num, i;
-+ char line[52], *p;
-+
-+ if (length >= 512)
-+ return;
-+ start = 0;
-+ while (length > 0) {
-+ num = length < 16u ? length : 16u;
-+ p = line;
-+ for (i = 0; i < num; ++i) {
-+ if (i == 8)
-+ *p++ = ' ';
-+ DWC_SPRINTF(p, " %02x", buf[i]);
-+ p += 3;
-+ }
-+ *p = 0;
-+ DWC_PRINTF("%6x: %s\n", start, line);
-+ buf += num;
-+ start += num;
-+ length -= num;
-+ }
-+}
-+#else
-+static inline void dump_msg(const u8 * buf, unsigned int length)
-+{
-+}
-+#endif
-+
-+/**
-+ * This function writes a packet into the Tx FIFO associated with the
-+ * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
-+ * periodic EPs the periodic Tx FIFO associated with the EP is written
-+ * with all packets for the next micro-frame.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to write packet for.
-+ * @param dma Indicates if DMA is being used.
-+ */
-+void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
-+ int dma)
-+{
-+ /**
-+ * The buffer is padded to DWORD on a per packet basis in
-+ * slave/dma mode if the MPS is not DWORD aligned. The last
-+ * packet, if short, is also padded to a multiple of DWORD.
-+ *
-+ * ep->xfer_buff always starts DWORD aligned in memory and is a
-+ * multiple of DWORD in length
-+ *
-+ * ep->xfer_len can be any number of bytes
-+ *
-+ * ep->xfer_count is a multiple of ep->maxpacket until the last
-+ * packet
-+ *
-+ * FIFO access is DWORD */
-+
-+ uint32_t i;
-+ uint32_t byte_count;
-+ uint32_t dword_count;
-+ uint32_t *fifo;
-+ uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
-+
-+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
-+ ep);
-+ if (ep->xfer_count >= ep->xfer_len) {
-+ DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
-+ return;
-+ }
-+
-+ /* Find the byte length of the packet either short packet or MPS */
-+ if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
-+ byte_count = ep->xfer_len - ep->xfer_count;
-+ } else {
-+ byte_count = ep->maxpacket;
-+ }
-+
-+ /* Find the DWORD length, padded by extra bytes as neccessary if MPS
-+ * is not a multiple of DWORD */
-+ dword_count = (byte_count + 3) / 4;
-+
-+#ifdef VERBOSE
-+ dump_msg(ep->xfer_buff, byte_count);
-+#endif
-+
-+ /**@todo NGS Where are the Periodic Tx FIFO addresses
-+ * intialized? What should this be? */
-+
-+ fifo = core_if->data_fifo[ep->num];
-+
-+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
-+ fifo, data_buff, *data_buff, byte_count);
-+
-+ if (!dma) {
-+ for (i = 0; i < dword_count; i++, data_buff++) {
-+ DWC_WRITE_REG32(fifo, *data_buff);
-+ }
-+ }
-+
-+ ep->xfer_count += byte_count;
-+ ep->xfer_buff += byte_count;
-+ ep->dma_addr += byte_count;
-+}
-+
-+/**
-+ * Set the EP STALL.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to set the stall on.
-+ */
-+void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl;
-+ volatile uint32_t *depctl_addr;
-+
-+ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
-+ (ep->is_in ? "IN" : "OUT"));
-+
-+ if (ep->is_in == 1) {
-+ depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
-+ depctl.d32 = DWC_READ_REG32(depctl_addr);
-+
-+ /* set the disable and stall bits */
-+ if (depctl.b.epena) {
-+ depctl.b.epdis = 1;
-+ }
-+ depctl.b.stall = 1;
-+ DWC_WRITE_REG32(depctl_addr, depctl.d32);
-+ } else {
-+ depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
-+ depctl.d32 = DWC_READ_REG32(depctl_addr);
-+
-+ /* set the stall bit */
-+ depctl.b.stall = 1;
-+ DWC_WRITE_REG32(depctl_addr, depctl.d32);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
-+
-+ return;
-+}
-+
-+/**
-+ * Clear the EP STALL.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to clear stall from.
-+ */
-+void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl;
-+ volatile uint32_t *depctl_addr;
-+
-+ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
-+ (ep->is_in ? "IN" : "OUT"));
-+
-+ if (ep->is_in == 1) {
-+ depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
-+ } else {
-+ depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
-+ }
-+
-+ depctl.d32 = DWC_READ_REG32(depctl_addr);
-+
-+ /* clear the stall bits */
-+ depctl.b.stall = 0;
-+
-+ /*
-+ * USB Spec 9.4.5: For endpoints using data toggle, regardless
-+ * of whether an endpoint has the Halt feature set, a
-+ * ClearFeature(ENDPOINT_HALT) request always results in the
-+ * data toggle being reinitialized to DATA0.
-+ */
-+ if (ep->type == DWC_OTG_EP_TYPE_INTR ||
-+ ep->type == DWC_OTG_EP_TYPE_BULK) {
-+ depctl.b.setd0pid = 1; /* DATA0 */
-+ }
-+
-+ DWC_WRITE_REG32(depctl_addr, depctl.d32);
-+ DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
-+ return;
-+}
-+
-+/**
-+ * This function reads a packet from the Rx FIFO into the destination
-+ * buffer. To read SETUP data use dwc_otg_read_setup_packet.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param dest Destination buffer for the packet.
-+ * @param bytes Number of bytes to copy to the destination.
-+ */
-+void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
-+ uint8_t * dest, uint16_t bytes)
-+{
-+ int i;
-+ int word_count = (bytes + 3) / 4;
-+
-+ volatile uint32_t *fifo = core_if->data_fifo[0];
-+ uint32_t *data_buff = (uint32_t *) dest;
-+
-+ /**
-+ * @todo Account for the case where _dest is not dword aligned. This
-+ * requires reading data from the FIFO into a uint32_t temp buffer,
-+ * then moving it into the data buffer.
-+ */
-+
-+ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
-+ core_if, dest, bytes);
-+
-+ for (i = 0; i < word_count; i++, data_buff++) {
-+ *data_buff = DWC_READ_REG32(fifo);
-+ }
-+
-+ return;
-+}
-+
-+/**
-+ * This functions reads the device registers and prints them
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
-+{
-+ int i;
-+ volatile uint32_t *addr;
-+
-+ DWC_PRINTF("Device Global Registers\n");
-+ addr = &core_if->dev_if->dev_global_regs->dcfg;
-+ DWC_PRINTF("DCFG @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->dctl;
-+ DWC_PRINTF("DCTL @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->dsts;
-+ DWC_PRINTF("DSTS @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->diepmsk;
-+ DWC_PRINTF("DIEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->doepmsk;
-+ DWC_PRINTF("DOEPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->daint;
-+ DWC_PRINTF("DAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->daintmsk;
-+ DWC_PRINTF("DAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->dtknqr1;
-+ DWC_PRINTF("DTKNQR1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
-+ addr = &core_if->dev_if->dev_global_regs->dtknqr2;
-+ DWC_PRINTF("DTKNQR2 @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ }
-+
-+ addr = &core_if->dev_if->dev_global_regs->dvbusdis;
-+ DWC_PRINTF("DVBUSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+
-+ addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
-+ DWC_PRINTF("DVBUSPULSE @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+
-+ addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
-+ DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+
-+ if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
-+ addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
-+ DWC_PRINTF("DTKNQR4 @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ }
-+
-+ addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
-+ DWC_PRINTF("FIFOEMPMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+
-+ if (core_if->hwcfg2.b.multi_proc_int) {
-+
-+ addr = &core_if->dev_if->dev_global_regs->deachint;
-+ DWC_PRINTF("DEACHINT @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->dev_global_regs->deachintmsk;
-+ DWC_PRINTF("DEACHINTMSK @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+
-+ for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
-+ addr =
-+ &core_if->dev_if->
-+ dev_global_regs->diepeachintmsk[i];
-+ DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
-+ i, (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ }
-+
-+ for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
-+ addr =
-+ &core_if->dev_if->
-+ dev_global_regs->doepeachintmsk[i];
-+ DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08lX : 0x%08X\n",
-+ i, (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ }
-+ }
-+
-+ for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_PRINTF("Device IN EP %d Registers\n", i);
-+ addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
-+ DWC_PRINTF("DIEPCTL @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->in_ep_regs[i]->diepint;
-+ DWC_PRINTF("DIEPINT @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
-+ DWC_PRINTF("DIETSIZ @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
-+ DWC_PRINTF("DIEPDMA @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
-+ DWC_PRINTF("DTXFSTS @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
-+ DWC_PRINTF("DIEPDMAB @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, 0 /*DWC_READ_REG32(addr) */ );
-+ }
-+
-+ for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
-+ DWC_PRINTF("Device OUT EP %d Registers\n", i);
-+ addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
-+ DWC_PRINTF("DOEPCTL @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->out_ep_regs[i]->doepint;
-+ DWC_PRINTF("DOEPINT @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
-+ DWC_PRINTF("DOETSIZ @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
-+ DWC_PRINTF("DOEPDMA @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */
-+ addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
-+ DWC_PRINTF("DOEPDMAB @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ }
-+
-+ }
-+}
-+
-+/**
-+ * This functions reads the SPRAM and prints its content
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
-+{
-+ volatile uint8_t *addr, *start_addr, *end_addr;
-+
-+ DWC_PRINTF("SPRAM Data:\n");
-+ start_addr = (void *)core_if->core_global_regs;
-+ DWC_PRINTF("Base Address: 0x%8lX\n", (unsigned long)start_addr);
-+ start_addr += 0x00028000;
-+ end_addr = (void *)core_if->core_global_regs;
-+ end_addr += 0x000280e0;
-+
-+ for (addr = start_addr; addr < end_addr; addr += 16) {
-+ DWC_PRINTF
-+ ("0x%8lX:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
-+ (unsigned long)addr, addr[0], addr[1], addr[2], addr[3],
-+ addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
-+ addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
-+ );
-+ }
-+
-+ return;
-+}
-+
-+/**
-+ * This function reads the host registers and prints them
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
-+{
-+ int i;
-+ volatile uint32_t *addr;
-+
-+ DWC_PRINTF("Host Global Registers\n");
-+ addr = &core_if->host_if->host_global_regs->hcfg;
-+ DWC_PRINTF("HCFG @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->host_global_regs->hfir;
-+ DWC_PRINTF("HFIR @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->host_global_regs->hfnum;
-+ DWC_PRINTF("HFNUM @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->host_global_regs->hptxsts;
-+ DWC_PRINTF("HPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->host_global_regs->haint;
-+ DWC_PRINTF("HAINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->host_global_regs->haintmsk;
-+ DWC_PRINTF("HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ if (core_if->dma_desc_enable) {
-+ addr = &core_if->host_if->host_global_regs->hflbaddr;
-+ DWC_PRINTF("HFLBADDR @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ }
-+
-+ addr = core_if->host_if->hprt0;
-+ DWC_PRINTF("HPRT0 @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+
-+ for (i = 0; i < core_if->core_params->host_channels; i++) {
-+ DWC_PRINTF("Host Channel %d Specific Registers\n", i);
-+ addr = &core_if->host_if->hc_regs[i]->hcchar;
-+ DWC_PRINTF("HCCHAR @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->hc_regs[i]->hcsplt;
-+ DWC_PRINTF("HCSPLT @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->hc_regs[i]->hcint;
-+ DWC_PRINTF("HCINT @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->hc_regs[i]->hcintmsk;
-+ DWC_PRINTF("HCINTMSK @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->hc_regs[i]->hctsiz;
-+ DWC_PRINTF("HCTSIZ @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->host_if->hc_regs[i]->hcdma;
-+ DWC_PRINTF("HCDMA @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ if (core_if->dma_desc_enable) {
-+ addr = &core_if->host_if->hc_regs[i]->hcdmab;
-+ DWC_PRINTF("HCDMAB @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ }
-+
-+ }
-+ return;
-+}
-+
-+/**
-+ * This function reads the core global registers and prints them
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
-+{
-+ int i, ep_num;
-+ volatile uint32_t *addr;
-+ char *txfsiz;
-+
-+ DWC_PRINTF("Core Global Registers\n");
-+ addr = &core_if->core_global_regs->gotgctl;
-+ DWC_PRINTF("GOTGCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gotgint;
-+ DWC_PRINTF("GOTGINT @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gahbcfg;
-+ DWC_PRINTF("GAHBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gusbcfg;
-+ DWC_PRINTF("GUSBCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->grstctl;
-+ DWC_PRINTF("GRSTCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gintsts;
-+ DWC_PRINTF("GINTSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gintmsk;
-+ DWC_PRINTF("GINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->grxstsr;
-+ DWC_PRINTF("GRXSTSR @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->grxfsiz;
-+ DWC_PRINTF("GRXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gnptxfsiz;
-+ DWC_PRINTF("GNPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gnptxsts;
-+ DWC_PRINTF("GNPTXSTS @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gi2cctl;
-+ DWC_PRINTF("GI2CCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gpvndctl;
-+ DWC_PRINTF("GPVNDCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->ggpio;
-+ DWC_PRINTF("GGPIO @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->guid;
-+ DWC_PRINTF("GUID @0x%08lX : 0x%08X\n",
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gsnpsid;
-+ DWC_PRINTF("GSNPSID @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->ghwcfg1;
-+ DWC_PRINTF("GHWCFG1 @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->ghwcfg2;
-+ DWC_PRINTF("GHWCFG2 @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->ghwcfg3;
-+ DWC_PRINTF("GHWCFG3 @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->ghwcfg4;
-+ DWC_PRINTF("GHWCFG4 @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->glpmcfg;
-+ DWC_PRINTF("GLPMCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gpwrdn;
-+ DWC_PRINTF("GPWRDN @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->gdfifocfg;
-+ DWC_PRINTF("GDFIFOCFG @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+ addr = &core_if->core_global_regs->adpctl;
-+ DWC_PRINTF("ADPCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ dwc_otg_adp_read_reg(core_if));
-+ addr = &core_if->core_global_regs->hptxfsiz;
-+ DWC_PRINTF("HPTXFSIZ @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ ep_num = core_if->hwcfg4.b.num_dev_perio_in_ep;
-+ txfsiz = "DPTXFSIZ";
-+ } else {
-+ ep_num = core_if->hwcfg4.b.num_in_eps;
-+ txfsiz = "DIENPTXF";
-+ }
-+ for (i = 0; i < ep_num; i++) {
-+ addr = &core_if->core_global_regs->dtxfsiz[i];
-+ DWC_PRINTF("%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
-+ (unsigned long)addr, DWC_READ_REG32(addr));
-+ }
-+ addr = core_if->pcgcctl;
-+ DWC_PRINTF("PCGCCTL @0x%08lX : 0x%08X\n", (unsigned long)addr,
-+ DWC_READ_REG32(addr));
-+}
-+
-+/**
-+ * Flush a Tx FIFO.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param num Tx FIFO to flush.
-+ */
-+void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ volatile grstctl_t greset = {.d32 = 0 };
-+ int count = 0;
-+
-+ DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
-+
-+ greset.b.txfflsh = 1;
-+ greset.b.txfnum = num;
-+ DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
-+
-+ do {
-+ greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
-+ if (++count > 10000) {
-+ DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
-+ __func__, greset.d32,
-+ DWC_READ_REG32(&global_regs->gnptxsts));
-+ break;
-+ }
-+ dwc_udelay(1);
-+ } while (greset.b.txfflsh == 1);
-+
-+ /* Wait for 3 PHY Clocks */
-+ dwc_udelay(1);
-+}
-+
-+/**
-+ * Flush Rx FIFO.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ volatile grstctl_t greset = {.d32 = 0 };
-+ int count = 0;
-+
-+ DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
-+ /*
-+ *
-+ */
-+ greset.b.rxfflsh = 1;
-+ DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
-+
-+ do {
-+ greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
-+ if (++count > 10000) {
-+ DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
-+ greset.d32);
-+ break;
-+ }
-+ dwc_udelay(1);
-+ } while (greset.b.rxfflsh == 1);
-+
-+ /* Wait for 3 PHY Clocks */
-+ dwc_udelay(1);
-+}
-+
-+/**
-+ * Do core a soft reset of the core. Be careful with this because it
-+ * resets all the internal state machines of the core.
-+ */
-+void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ volatile grstctl_t greset = {.d32 = 0 };
-+ int count = 0;
-+
-+ DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
-+ /* Wait for AHB master IDLE state. */
-+ do {
-+ dwc_udelay(10);
-+ greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
-+ if (++count > 100000) {
-+ DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
-+ greset.d32);
-+ return;
-+ }
-+ }
-+ while (greset.b.ahbidle == 0);
-+
-+ /* Core Soft Reset */
-+ count = 0;
-+ greset.b.csftrst = 1;
-+ DWC_WRITE_REG32(&global_regs->grstctl, greset.d32);
-+ do {
-+ greset.d32 = DWC_READ_REG32(&global_regs->grstctl);
-+ if (++count > 10000) {
-+ DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
-+ __func__, greset.d32);
-+ break;
-+ }
-+ dwc_udelay(1);
-+ }
-+ while (greset.b.csftrst == 1);
-+
-+ /* Wait for 3 PHY Clocks */
-+ dwc_mdelay(100);
-+}
-+
-+uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
-+{
-+ return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
-+}
-+
-+uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
-+{
-+ return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
-+}
-+
-+/**
-+ * Register HCD callbacks. The callbacks are used to start and stop
-+ * the HCD for interrupt processing.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param cb the HCD callback structure.
-+ * @param p pointer to be passed to callback function (usb_hcd*).
-+ */
-+void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
-+ dwc_otg_cil_callbacks_t * cb, void *p)
-+{
-+ core_if->hcd_cb = cb;
-+ cb->p = p;
-+}
-+
-+/**
-+ * Register PCD callbacks. The callbacks are used to start and stop
-+ * the PCD for interrupt processing.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param cb the PCD callback structure.
-+ * @param p pointer to be passed to callback function (pcd*).
-+ */
-+void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
-+ dwc_otg_cil_callbacks_t * cb, void *p)
-+{
-+ core_if->pcd_cb = cb;
-+ cb->p = p;
-+}
-+
-+#ifdef DWC_EN_ISOC
-+
-+/**
-+ * This function writes isoc data per 1 (micro)frame into tx fifo
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ *
-+ */
-+void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ dwc_otg_dev_in_ep_regs_t *ep_regs;
-+ dtxfsts_data_t txstatus = {.d32 = 0 };
-+ uint32_t len = 0;
-+ uint32_t dwords;
-+
-+ ep->xfer_len = ep->data_per_frame;
-+ ep->xfer_count = 0;
-+
-+ ep_regs = core_if->dev_if->in_ep_regs[ep->num];
-+
-+ len = ep->xfer_len - ep->xfer_count;
-+
-+ if (len > ep->maxpacket) {
-+ len = ep->maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+
-+ /* While there is space in the queue and space in the FIFO and
-+ * More data to tranfer, Write packets to the Tx FIFO */
-+ txstatus.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
-+ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
-+
-+ while (txstatus.b.txfspcavail > dwords &&
-+ ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
-+ /* Write the FIFO */
-+ dwc_otg_ep_write_packet(core_if, ep, 0);
-+
-+ len = ep->xfer_len - ep->xfer_count;
-+ if (len > ep->maxpacket) {
-+ len = ep->maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+ txstatus.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ dtxfsts);
-+ DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
-+ txstatus.d32);
-+ }
-+}
-+
-+/**
-+ * This function initializes a descriptor chain for Isochronous transfer
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ *
-+ */
-+void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * ep)
-+{
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dsts_data_t dsts = {.d32 = 0 };
-+ volatile uint32_t *addr;
-+
-+ if (ep->is_in) {
-+ addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
-+ } else {
-+ addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
-+ }
-+
-+ ep->xfer_len = ep->data_per_frame;
-+ ep->xfer_count = 0;
-+ ep->xfer_buff = ep->cur_pkt_addr;
-+ ep->dma_addr = ep->cur_pkt_dma_addr;
-+
-+ if (ep->is_in) {
-+ /* Program the transfer size and packet count
-+ * as follows: xfersize = N * maxpacket +
-+ * short_packet pktcnt = N + (short_packet
-+ * exist ? 1 : 0)
-+ */
-+ deptsiz.b.xfersize = ep->xfer_len;
-+ deptsiz.b.pktcnt =
-+ (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
-+ deptsiz.b.mc = deptsiz.b.pktcnt;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
-+ deptsiz.d32);
-+
-+ /* Write the DMA register */
-+ if (core_if->dma_enable) {
-+ DWC_WRITE_REG32(&
-+ (core_if->dev_if->in_ep_regs[ep->num]->
-+ diepdma), (uint32_t) ep->dma_addr);
-+ }
-+ } else {
-+ deptsiz.b.pktcnt =
-+ (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
-+ deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
-+
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ out_ep_regs[ep->num]->doeptsiz, deptsiz.d32);
-+
-+ if (core_if->dma_enable) {
-+ DWC_WRITE_REG32(&
-+ (core_if->dev_if->
-+ out_ep_regs[ep->num]->doepdma),
-+ (uint32_t) ep->dma_addr);
-+ }
-+ }
-+
-+ /** Enable endpoint, clear nak */
-+
-+ depctl.d32 = 0;
-+ if (ep->bInterval == 1) {
-+ dsts.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+ ep->next_frame = dsts.b.soffn + ep->bInterval;
-+
-+ if (ep->next_frame & 0x1) {
-+ depctl.b.setd1pid = 1;
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ }
-+ } else {
-+ ep->next_frame += ep->bInterval;
-+
-+ if (ep->next_frame & 0x1) {
-+ depctl.b.setd1pid = 1;
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ }
-+ }
-+ depctl.b.epena = 1;
-+ depctl.b.cnak = 1;
-+
-+ DWC_MODIFY_REG32(addr, 0, depctl.d32);
-+ depctl.d32 = DWC_READ_REG32(addr);
-+
-+ if (ep->is_in && core_if->dma_enable == 0) {
-+ write_isoc_frame_data(core_if, ep);
-+ }
-+
-+}
-+#endif /* DWC_EN_ISOC */
-+
-+static void dwc_otg_set_uninitialized(int32_t * p, int size)
-+{
-+ int i;
-+ for (i = 0; i < size; i++) {
-+ p[i] = -1;
-+ }
-+}
-+
-+static int dwc_otg_param_initialized(int32_t val)
-+{
-+ return val != -1;
-+}
-+
-+static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
-+{
-+ int i;
-+ core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
-+ if (!core_if->core_params) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
-+ sizeof(*core_if->core_params) /
-+ sizeof(int32_t));
-+ DWC_PRINTF("Setting default values for core params\n");
-+ dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
-+ dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
-+ dwc_otg_set_param_dma_desc_enable(core_if,
-+ dwc_param_dma_desc_enable_default);
-+ dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
-+ dwc_otg_set_param_dma_burst_size(core_if,
-+ dwc_param_dma_burst_size_default);
-+ dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
-+ dwc_param_host_support_fs_ls_low_power_default);
-+ dwc_otg_set_param_enable_dynamic_fifo(core_if,
-+ dwc_param_enable_dynamic_fifo_default);
-+ dwc_otg_set_param_data_fifo_size(core_if,
-+ dwc_param_data_fifo_size_default);
-+ dwc_otg_set_param_dev_rx_fifo_size(core_if,
-+ dwc_param_dev_rx_fifo_size_default);
-+ dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
-+ dwc_param_dev_nperio_tx_fifo_size_default);
-+ dwc_otg_set_param_host_rx_fifo_size(core_if,
-+ dwc_param_host_rx_fifo_size_default);
-+ dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
-+ dwc_param_host_nperio_tx_fifo_size_default);
-+ dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
-+ dwc_param_host_perio_tx_fifo_size_default);
-+ dwc_otg_set_param_max_transfer_size(core_if,
-+ dwc_param_max_transfer_size_default);
-+ dwc_otg_set_param_max_packet_count(core_if,
-+ dwc_param_max_packet_count_default);
-+ dwc_otg_set_param_host_channels(core_if,
-+ dwc_param_host_channels_default);
-+ dwc_otg_set_param_dev_endpoints(core_if,
-+ dwc_param_dev_endpoints_default);
-+ dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
-+ dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
-+ dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
-+ dwc_param_host_ls_low_power_phy_clk_default);
-+ dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
-+ dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
-+ dwc_param_phy_ulpi_ext_vbus_default);
-+ dwc_otg_set_param_phy_utmi_width(core_if,
-+ dwc_param_phy_utmi_width_default);
-+ dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
-+ dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
-+ dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
-+ dwc_otg_set_param_en_multiple_tx_fifo(core_if,
-+ dwc_param_en_multiple_tx_fifo_default);
-+ for (i = 0; i < 15; i++) {
-+ dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
-+ dwc_param_dev_perio_tx_fifo_size_default,
-+ i);
-+ }
-+
-+ for (i = 0; i < 15; i++) {
-+ dwc_otg_set_param_dev_tx_fifo_size(core_if,
-+ dwc_param_dev_tx_fifo_size_default,
-+ i);
-+ }
-+ dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
-+ dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
-+ dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
-+ dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
-+ dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
-+ dwc_otg_set_param_tx_thr_length(core_if,
-+ dwc_param_tx_thr_length_default);
-+ dwc_otg_set_param_rx_thr_length(core_if,
-+ dwc_param_rx_thr_length_default);
-+ dwc_otg_set_param_ahb_thr_ratio(core_if,
-+ dwc_param_ahb_thr_ratio_default);
-+ dwc_otg_set_param_power_down(core_if, dwc_param_power_down_default);
-+ dwc_otg_set_param_reload_ctl(core_if, dwc_param_reload_ctl_default);
-+ dwc_otg_set_param_dev_out_nak(core_if, dwc_param_dev_out_nak_default);
-+ dwc_otg_set_param_cont_on_bna(core_if, dwc_param_cont_on_bna_default);
-+ dwc_otg_set_param_ahb_single(core_if, dwc_param_ahb_single_default);
-+ dwc_otg_set_param_otg_ver(core_if, dwc_param_otg_ver_default);
-+ dwc_otg_set_param_adp_enable(core_if, dwc_param_adp_enable_default);
-+ DWC_PRINTF("Finished setting default values for core params\n");
-+
-+ return 0;
-+}
-+
-+uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->dma_enable;
-+}
-+
-+/* Checks if the parameter is outside of its valid range of values */
-+#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
-+ (((_param_) < (_low_)) || \
-+ ((_param_) > (_high_)))
-+
-+/* Parameter access functions */
-+int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int valid;
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
-+ DWC_WARN("Wrong value for otg_cap parameter\n");
-+ DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
-+ retval = -DWC_E_INVALID;
-+ goto out;
-+ }
-+
-+ valid = 1;
-+ switch (val) {
-+ case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
-+ if (core_if->hwcfg2.b.op_mode !=
-+ DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
-+ valid = 0;
-+ break;
-+ case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
-+ if ((core_if->hwcfg2.b.op_mode !=
-+ DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
-+ && (core_if->hwcfg2.b.op_mode !=
-+ DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
-+ && (core_if->hwcfg2.b.op_mode !=
-+ DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
-+ && (core_if->hwcfg2.b.op_mode !=
-+ DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
-+ valid = 0;
-+ }
-+ break;
-+ case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
-+ /* always valid */
-+ break;
-+ }
-+ if (!valid) {
-+ if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
-+ DWC_ERROR
-+ ("%d invalid for otg_cap paremter. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ (((core_if->hwcfg2.b.op_mode ==
-+ DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
-+ || (core_if->hwcfg2.b.op_mode ==
-+ DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
-+ || (core_if->hwcfg2.b.op_mode ==
-+ DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
-+ || (core_if->hwcfg2.b.op_mode ==
-+ DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
-+ DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
-+ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->otg_cap = val;
-+out:
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->otg_cap;
-+}
-+
-+int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for opt parameter\n");
-+ return -DWC_E_INVALID;
-+ }
-+ core_if->core_params->opt = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->opt;
-+}
-+
-+int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for dma enable\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
-+ if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for dma_enable paremter. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->dma_enable = val;
-+ if (val == 0) {
-+ dwc_otg_set_param_dma_desc_enable(core_if, 0);
-+ }
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dma_enable;
-+}
-+
-+int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for dma_enable\n");
-+ DWC_WARN("dma_desc_enable must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1)
-+ && ((dwc_otg_get_param_dma_enable(core_if) == 0)
-+ || (core_if->hwcfg4.b.desc_dma == 0))) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->dma_desc_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+ core_if->core_params->dma_desc_enable = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dma_desc_enable;
-+}
-+
-+int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for host_support_fs_low_power\n");
-+ DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+ core_if->core_params->host_support_fs_ls_low_power = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
-+ core_if)
-+{
-+ return core_if->core_params->host_support_fs_ls_low_power;
-+}
-+
-+int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for enable_dynamic_fifo\n");
-+ DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->enable_dynamic_fifo)) {
-+ DWC_ERROR
-+ ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+ core_if->core_params->enable_dynamic_fifo = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->enable_dynamic_fifo;
-+}
-+
-+int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
-+ DWC_WARN("Wrong value for data_fifo_size\n");
-+ DWC_WARN("data_fifo_size must be 32-32768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > core_if->hwcfg3.b.dfifo_depth) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->data_fifo_size)) {
-+ DWC_ERROR
-+ ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
-+ val);
-+ }
-+ val = core_if->hwcfg3.b.dfifo_depth;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->data_fifo_size = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->data_fifo_size;
-+}
-+
-+int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
-+ DWC_WARN("Wrong value for dev_rx_fifo_size\n");
-+ DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
-+ if (dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
-+ DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
-+ }
-+ val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->dev_rx_fifo_size = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dev_rx_fifo_size;
-+}
-+
-+int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
-+ DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
-+ DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->dev_nperio_tx_fifo_size)) {
-+ DWC_ERROR
-+ ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
-+ 16);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->dev_nperio_tx_fifo_size = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dev_nperio_tx_fifo_size;
-+}
-+
-+int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
-+ DWC_WARN("Wrong value for host_rx_fifo_size\n");
-+ DWC_WARN("host_rx_fifo_size must be 16-32768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > DWC_READ_REG32(&core_if->core_global_regs->grxfsiz)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->host_rx_fifo_size)) {
-+ DWC_ERROR
-+ ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
-+ val);
-+ }
-+ val = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->host_rx_fifo_size = val;
-+ return retval;
-+
-+}
-+
-+int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->host_rx_fifo_size;
-+}
-+
-+int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
-+ DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
-+ DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->host_nperio_tx_fifo_size)) {
-+ DWC_ERROR
-+ ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ (DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz) >>
-+ 16);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->host_nperio_tx_fifo_size = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->host_nperio_tx_fifo_size;
-+}
-+
-+int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
-+ DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
-+ DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > ((core_if->hptxfsiz.d32) >> 16)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->host_perio_tx_fifo_size)) {
-+ DWC_ERROR
-+ ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
-+ val);
-+ }
-+ val = (core_if->hptxfsiz.d32) >> 16;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->host_perio_tx_fifo_size = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->host_perio_tx_fifo_size;
-+}
-+
-+int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
-+ DWC_WARN("Wrong value for max_transfer_size\n");
-+ DWC_WARN("max_transfer_size must be 2047-524288\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->max_transfer_size)) {
-+ DWC_ERROR
-+ ("%d invalid for max_transfer_size. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
-+ 1);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->max_transfer_size = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->max_transfer_size;
-+}
-+
-+int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
-+ DWC_WARN("Wrong value for max_packet_count\n");
-+ DWC_WARN("max_packet_count must be 15-511\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->max_packet_count)) {
-+ DWC_ERROR
-+ ("%d invalid for max_packet_count. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->max_packet_count = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->max_packet_count;
-+}
-+
-+int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
-+ DWC_WARN("Wrong value for host_channels\n");
-+ DWC_WARN("host_channels must be 1-16\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->host_channels)) {
-+ DWC_ERROR
-+ ("%d invalid for host_channels. Check HW configurations.\n",
-+ val);
-+ }
-+ val = (core_if->hwcfg2.b.num_host_chan + 1);
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->host_channels = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->host_channels;
-+}
-+
-+int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
-+ DWC_WARN("Wrong value for dev_endpoints\n");
-+ DWC_WARN("dev_endpoints must be 1-15\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val > (core_if->hwcfg2.b.num_dev_ep)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->dev_endpoints)) {
-+ DWC_ERROR
-+ ("%d invalid for dev_endpoints. Check HW configurations.\n",
-+ val);
-+ }
-+ val = core_if->hwcfg2.b.num_dev_ep;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->dev_endpoints = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dev_endpoints;
-+}
-+
-+int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
-+ DWC_WARN("Wrong value for phy_type\n");
-+ DWC_WARN("phy_type must be 0,1 or 2\n");
-+ return -DWC_E_INVALID;
-+ }
-+#ifndef NO_FS_PHY_HW_CHECKS
-+ if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
-+ ((core_if->hwcfg2.b.hs_phy_type == 1) ||
-+ (core_if->hwcfg2.b.hs_phy_type == 3))) {
-+ valid = 1;
-+ } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
-+ ((core_if->hwcfg2.b.hs_phy_type == 2) ||
-+ (core_if->hwcfg2.b.hs_phy_type == 3))) {
-+ valid = 1;
-+ } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
-+ (core_if->hwcfg2.b.fs_phy_type == 1)) {
-+ valid = 1;
-+ }
-+ if (!valid) {
-+ if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
-+ DWC_ERROR
-+ ("%d invalid for phy_type. Check HW configurations.\n",
-+ val);
-+ }
-+ if (core_if->hwcfg2.b.hs_phy_type) {
-+ if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
-+ (core_if->hwcfg2.b.hs_phy_type == 1)) {
-+ val = DWC_PHY_TYPE_PARAM_UTMI;
-+ } else {
-+ val = DWC_PHY_TYPE_PARAM_ULPI;
-+ }
-+ }
-+ retval = -DWC_E_INVALID;
-+ }
-+#endif
-+ core_if->core_params->phy_type = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->phy_type;
-+}
-+
-+int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for speed parameter\n");
-+ DWC_WARN("max_speed parameter must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+ if ((val == 0)
-+ && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
-+ if (dwc_otg_param_initialized(core_if->core_params->speed)) {
-+ DWC_ERROR
-+ ("%d invalid for speed paremter. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ (dwc_otg_get_param_phy_type(core_if) ==
-+ DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
-+ retval = -DWC_E_INVALID;
-+ }
-+ core_if->core_params->speed = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->speed;
-+}
-+
-+int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN
-+ ("Wrong value for host_ls_low_power_phy_clk parameter\n");
-+ DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
-+ && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->host_ls_low_power_phy_clk)) {
-+ DWC_ERROR
-+ ("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
-+ val);
-+ }
-+ val =
-+ (dwc_otg_get_param_phy_type(core_if) ==
-+ DWC_PHY_TYPE_PARAM_FS) ?
-+ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
-+ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->host_ls_low_power_phy_clk = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->host_ls_low_power_phy_clk;
-+}
-+
-+int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for phy_ulpi_ddr\n");
-+ DWC_WARN("phy_upli_ddr must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->phy_ulpi_ddr = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->phy_ulpi_ddr;
-+}
-+
-+int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
-+ DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->phy_ulpi_ext_vbus = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->phy_ulpi_ext_vbus;
-+}
-+
-+int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
-+ DWC_WARN("Wrong valaue for phy_utmi_width\n");
-+ DWC_WARN("phy_utmi_width must be 8 or 16\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->phy_utmi_width = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->phy_utmi_width;
-+}
-+
-+int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
-+ DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->ulpi_fs_ls = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->ulpi_fs_ls;
-+}
-+
-+int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong valaue for ts_dline\n");
-+ DWC_WARN("ts_dline must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->ts_dline = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->ts_dline;
-+}
-+
-+int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong valaue for i2c_enable\n");
-+ DWC_WARN("i2c_enable must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+#ifndef NO_FS_PHY_HW_CHECK
-+ if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
-+ if (dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for i2c_enable. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+#endif
-+
-+ core_if->core_params->i2c_enable = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->i2c_enable;
-+}
-+
-+int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val, int fifo_num)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
-+ DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
-+ DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val >
-+ (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
-+ DWC_ERROR
-+ ("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
-+ val, fifo_num);
-+ }
-+ val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int fifo_num)
-+{
-+ return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
-+}
-+
-+int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
-+ int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
-+ DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->en_multiple_tx_fifo)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->en_multiple_tx_fifo = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->en_multiple_tx_fifo;
-+}
-+
-+int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
-+ int fifo_num)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
-+ DWC_WARN("Wrong value for dev_tx_fifo_size\n");
-+ DWC_WARN("dev_tx_fifo_size must be 4-768\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val >
-+ (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]))) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->dev_tx_fifo_size[fifo_num])) {
-+ DWC_ERROR
-+ ("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
-+ val, fifo_num);
-+ }
-+ val = (DWC_READ_REG32(&core_if->core_global_regs->dtxfsiz[fifo_num]));
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int fifo_num)
-+{
-+ return core_if->core_params->dev_tx_fifo_size[fifo_num];
-+}
-+
-+int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
-+ DWC_WARN("Wrong value for thr_ctl\n");
-+ DWC_WARN("thr_ctl must be 0-7\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val != 0) &&
-+ (!dwc_otg_get_param_dma_enable(core_if) ||
-+ !core_if->hwcfg4.b.ded_fifo_en)) {
-+ if (dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter thr_ctl. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->thr_ctl = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->thr_ctl;
-+}
-+
-+int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("Wrong value for lpm_enable\n");
-+ DWC_WARN("lpm_enable must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val && !core_if->hwcfg3.b.otg_lpm_en) {
-+ if (dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter lpm_enable. Check HW configuration.\n",
-+ val);
-+ }
-+ val = 0;
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->lpm_enable = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->lpm_enable;
-+}
-+
-+int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
-+ DWC_WARN("Wrong valaue for tx_thr_length\n");
-+ DWC_WARN("tx_thr_length must be 8 - 128\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->tx_thr_length = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->tx_thr_length;
-+}
-+
-+int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
-+ DWC_WARN("Wrong valaue for rx_thr_length\n");
-+ DWC_WARN("rx_thr_length must be 8 - 128\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->rx_thr_length = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->rx_thr_length;
-+}
-+
-+int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
-+ DWC_OTG_PARAM_TEST(val, 4, 4) &&
-+ DWC_OTG_PARAM_TEST(val, 8, 8) &&
-+ DWC_OTG_PARAM_TEST(val, 16, 16) &&
-+ DWC_OTG_PARAM_TEST(val, 32, 32) &&
-+ DWC_OTG_PARAM_TEST(val, 64, 64) &&
-+ DWC_OTG_PARAM_TEST(val, 128, 128) &&
-+ DWC_OTG_PARAM_TEST(val, 256, 256)) {
-+ DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
-+ return -DWC_E_INVALID;
-+ }
-+ core_if->core_params->dma_burst_size = val;
-+ return 0;
-+}
-+
-+int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dma_burst_size;
-+}
-+
-+int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
-+ return -DWC_E_INVALID;
-+ }
-+ if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
-+ if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter pti_enable. Check HW configuration.\n",
-+ val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->pti_enable = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->pti_enable;
-+}
-+
-+int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
-+ return -DWC_E_INVALID;
-+ }
-+ if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
-+ if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter mpi_enable. Check HW configuration.\n",
-+ val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->mpi_enable = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->mpi_enable;
-+}
-+
-+int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `adp_enable'\n", val);
-+ return -DWC_E_INVALID;
-+ }
-+ if (val && (core_if->hwcfg3.b.adp_supp == 0)) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->adp_supp_enable)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter adp_enable. Check HW configuration.\n",
-+ val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->adp_supp_enable = val;
-+ /*Set OTG version 2.0 in case of enabling ADP*/
-+ if (val)
-+ dwc_otg_set_param_otg_ver(core_if, 1);
-+
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->adp_supp_enable;
-+}
-+
-+int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
-+ DWC_WARN("ic_usb_cap must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val && (core_if->hwcfg2.b.otg_enable_ic_usb == 0)) {
-+ if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
-+ val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->ic_usb_cap = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->ic_usb_cap;
-+}
-+
-+int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 1;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
-+ DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
-+ DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (val
-+ && (core_if->snpsid < OTG_CORE_REV_2_81a
-+ || !dwc_otg_get_param_thr_ctl(core_if))) {
-+ valid = 0;
-+ } else if (val
-+ && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) <
-+ 4)) {
-+ valid = 0;
-+ }
-+ if (valid == 0) {
-+ if (dwc_otg_param_initialized
-+ (core_if->core_params->ahb_thr_ratio)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter ahb_thr_ratio. Check HW configuration.\n",
-+ val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+
-+ core_if->core_params->ahb_thr_ratio = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->ahb_thr_ratio;
-+}
-+
-+int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 1;
-+ hwcfg4_data_t hwcfg4 = {.d32 = 0 };
-+ hwcfg4.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 3)) {
-+ DWC_WARN("`%d' invalid for parameter `power_down'\n", val);
-+ DWC_WARN("power_down must be 0 - 2\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 2) && (core_if->snpsid < OTG_CORE_REV_2_91a)) {
-+ valid = 0;
-+ }
-+ if ((val == 3)
-+ && ((core_if->snpsid < OTG_CORE_REV_3_00a)
-+ || (hwcfg4.b.xhiber == 0))) {
-+ valid = 0;
-+ }
-+ if (valid == 0) {
-+ if (dwc_otg_param_initialized(core_if->core_params->power_down)) {
-+ DWC_ERROR
-+ ("%d invalid for parameter power_down. Check HW configuration.\n",
-+ val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->power_down = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->power_down;
-+}
-+
-+int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 1;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `reload_ctl'\n", val);
-+ DWC_WARN("reload_ctl must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_92a)) {
-+ valid = 0;
-+ }
-+ if (valid == 0) {
-+ if (dwc_otg_param_initialized(core_if->core_params->reload_ctl)) {
-+ DWC_ERROR("%d invalid for parameter reload_ctl."
-+ "Check HW configuration.\n", val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->reload_ctl = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->reload_ctl;
-+}
-+
-+int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 1;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `dev_out_nak'\n", val);
-+ DWC_WARN("dev_out_nak must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_93a) ||
-+ !(core_if->core_params->dma_desc_enable))) {
-+ valid = 0;
-+ }
-+ if (valid == 0) {
-+ if (dwc_otg_param_initialized(core_if->core_params->dev_out_nak)) {
-+ DWC_ERROR("%d invalid for parameter dev_out_nak."
-+ "Check HW configuration.\n", val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->dev_out_nak = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->dev_out_nak;
-+}
-+
-+int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 1;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `cont_on_bna'\n", val);
-+ DWC_WARN("cont_on_bna must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1) && ((core_if->snpsid < OTG_CORE_REV_2_94a) ||
-+ !(core_if->core_params->dma_desc_enable))) {
-+ valid = 0;
-+ }
-+ if (valid == 0) {
-+ if (dwc_otg_param_initialized(core_if->core_params->cont_on_bna)) {
-+ DWC_ERROR("%d invalid for parameter cont_on_bna."
-+ "Check HW configuration.\n", val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->cont_on_bna = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->cont_on_bna;
-+}
-+
-+int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+ int valid = 1;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `ahb_single'\n", val);
-+ DWC_WARN("ahb_single must be 0 or 1\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if ((val == 1) && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
-+ valid = 0;
-+ }
-+ if (valid == 0) {
-+ if (dwc_otg_param_initialized(core_if->core_params->ahb_single)) {
-+ DWC_ERROR("%d invalid for parameter ahb_single."
-+ "Check HW configuration.\n", val);
-+ }
-+ retval = -DWC_E_INVALID;
-+ val = 0;
-+ }
-+ core_if->core_params->ahb_single = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->ahb_single;
-+}
-+
-+int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val)
-+{
-+ int retval = 0;
-+
-+ if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
-+ DWC_WARN("`%d' invalid for parameter `otg_ver'\n", val);
-+ DWC_WARN
-+ ("otg_ver must be 0(for OTG 1.3 support) or 1(for OTG 2.0 support)\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ core_if->core_params->otg_ver = val;
-+ return retval;
-+}
-+
-+int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->core_params->otg_ver;
-+}
-+
-+uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
-+{
-+ gotgctl_data_t otgctl;
-+ otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ return otgctl.b.hstnegscs;
-+}
-+
-+uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
-+{
-+ gotgctl_data_t otgctl;
-+ otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ return otgctl.b.sesreqscs;
-+}
-+
-+void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ if(core_if->otg_ver == 0) {
-+ gotgctl_data_t otgctl;
-+ otgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ otgctl.b.hnpreq = val;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, otgctl.d32);
-+ } else {
-+ core_if->otg_sts = val;
-+ }
-+}
-+
-+uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->snpsid;
-+}
-+
-+uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
-+{
-+ gintsts_data_t gintsts;
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ return gintsts.b.curmode;
-+}
-+
-+uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
-+{
-+ gusbcfg_data_t usbcfg;
-+ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ return usbcfg.b.hnpcap;
-+}
-+
-+void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ gusbcfg_data_t usbcfg;
-+ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ usbcfg.b.hnpcap = val;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
-+}
-+
-+uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
-+{
-+ gusbcfg_data_t usbcfg;
-+ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ return usbcfg.b.srpcap;
-+}
-+
-+void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ gusbcfg_data_t usbcfg;
-+ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ usbcfg.b.srpcap = val;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
-+}
-+
-+uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
-+{
-+ dcfg_data_t dcfg;
-+ /* originally: dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg); */
-+
-+ dcfg.d32 = -1; //GRAYG
-+ DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if);
-+ if (NULL == core_if)
-+ DWC_ERROR("reg request with NULL core_if\n");
-+ DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__,
-+ core_if, core_if->dev_if);
-+ if (NULL == core_if->dev_if)
-+ DWC_ERROR("reg request with NULL dev_if\n");
-+ DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->"
-+ "dev_global_regs(%p)\n", __func__,
-+ core_if, core_if->dev_if,
-+ core_if->dev_if->dev_global_regs);
-+ if (NULL == core_if->dev_if->dev_global_regs)
-+ DWC_ERROR("reg request with NULL dev_global_regs\n");
-+ else {
-+ DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->"
-+ "dev_global_regs(%p)->dcfg = %p\n", __func__,
-+ core_if, core_if->dev_if,
-+ core_if->dev_if->dev_global_regs,
-+ &core_if->dev_if->dev_global_regs->dcfg);
-+ dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ }
-+ return dcfg.b.devspd;
-+}
-+
-+void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ dcfg_data_t dcfg;
-+ dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ dcfg.b.devspd = val;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
-+}
-+
-+uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
-+ return hprt0.b.prtconnsts;
-+}
-+
-+uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
-+{
-+ dsts_data_t dsts;
-+ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+ return dsts.b.enumspd;
-+}
-+
-+uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
-+ return hprt0.b.prtpwr;
-+
-+}
-+
-+uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if)
-+{
-+ return core_if->hibernation_suspend;
-+}
-+
-+void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtpwr = val;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+}
-+
-+uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
-+ return hprt0.b.prtsusp;
-+
-+}
-+
-+void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtsusp = val;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+}
-+
-+uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if)
-+{
-+ hfir_data_t hfir;
-+ hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
-+ return hfir.b.frint;
-+
-+}
-+
-+void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ hfir_data_t hfir;
-+ uint32_t fram_int;
-+ fram_int = calc_frame_interval(core_if);
-+ hfir.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
-+ if (!core_if->core_params->reload_ctl) {
-+ DWC_WARN("\nCannot reload HFIR register.HFIR.HFIRRldCtrl bit is"
-+ "not set to 1.\nShould load driver with reload_ctl=1"
-+ " module parameter\n");
-+ return;
-+ }
-+ switch (fram_int) {
-+ case 3750:
-+ if ((val < 3350) || (val > 4150)) {
-+ DWC_WARN("HFIR interval for HS core and 30 MHz"
-+ "clock freq should be from 3350 to 4150\n");
-+ return;
-+ }
-+ break;
-+ case 30000:
-+ if ((val < 26820) || (val > 33180)) {
-+ DWC_WARN("HFIR interval for FS/LS core and 30 MHz"
-+ "clock freq should be from 26820 to 33180\n");
-+ return;
-+ }
-+ break;
-+ case 6000:
-+ if ((val < 5360) || (val > 6640)) {
-+ DWC_WARN("HFIR interval for HS core and 48 MHz"
-+ "clock freq should be from 5360 to 6640\n");
-+ return;
-+ }
-+ break;
-+ case 48000:
-+ if ((val < 42912) || (val > 53088)) {
-+ DWC_WARN("HFIR interval for FS/LS core and 48 MHz"
-+ "clock freq should be from 42912 to 53088\n");
-+ return;
-+ }
-+ break;
-+ case 7500:
-+ if ((val < 6700) || (val > 8300)) {
-+ DWC_WARN("HFIR interval for HS core and 60 MHz"
-+ "clock freq should be from 6700 to 8300\n");
-+ return;
-+ }
-+ break;
-+ case 60000:
-+ if ((val < 53640) || (val > 65536)) {
-+ DWC_WARN("HFIR interval for FS/LS core and 60 MHz"
-+ "clock freq should be from 53640 to 65536\n");
-+ return;
-+ }
-+ break;
-+ default:
-+ DWC_WARN("Unknown frame interval\n");
-+ return;
-+ break;
-+
-+ }
-+ hfir.b.frint = val;
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hfir.d32);
-+}
-+
-+uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if)
-+{
-+ hcfg_data_t hcfg;
-+ hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
-+ return hcfg.b.modechtimen;
-+
-+}
-+
-+void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ hcfg_data_t hcfg;
-+ hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
-+ hcfg.b.modechtimen = val;
-+ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
-+}
-+
-+void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtres = val;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+}
-+
-+uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
-+{
-+ dctl_data_t dctl;
-+ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
-+ return dctl.b.rmtwkupsig;
-+}
-+
-+uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+
-+ DWC_ASSERT(!
-+ ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
-+ "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
-+ core_if->lx_state, lpmcfg.b.prt_sleep_sts);
-+
-+ return lpmcfg.b.prt_sleep_sts;
-+}
-+
-+uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ return lpmcfg.b.rem_wkup_en;
-+}
-+
-+uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ return lpmcfg.b.appl_resp;
-+}
-+
-+void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ lpmcfg.b.appl_resp = val;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
-+}
-+
-+uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ return lpmcfg.b.hsic_connect;
-+}
-+
-+void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ lpmcfg.b.hsic_connect = val;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
-+}
-+
-+uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ return lpmcfg.b.inv_sel_hsic;
-+
-+}
-+
-+void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ lpmcfg.b.inv_sel_hsic = val;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
-+}
-+
-+uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+}
-+
-+void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, val);
-+}
-+
-+uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+}
-+
-+void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, val);
-+}
-+
-+uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
-+}
-+
-+void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, val);
-+}
-+
-+uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
-+}
-+
-+void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz, val);
-+}
-+
-+uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->gpvndctl);
-+}
-+
-+void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gpvndctl, val);
-+}
-+
-+uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->ggpio);
-+}
-+
-+void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, val);
-+}
-+
-+uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(core_if->host_if->hprt0);
-+
-+}
-+
-+void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, val);
-+}
-+
-+uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->guid);
-+}
-+
-+void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
-+{
-+ DWC_WRITE_REG32(&core_if->core_global_regs->guid, val);
-+}
-+
-+uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
-+{
-+ return DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
-+}
-+
-+uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if)
-+{
-+ return ((core_if->otg_ver == 1) ? (uint16_t)0x0200 : (uint16_t)0x0103);
-+}
-+
-+/**
-+ * Start the SRP timer to detect when the SRP does not complete within
-+ * 6 seconds.
-+ *
-+ * @param core_if the pointer to core_if strucure.
-+ */
-+void dwc_otg_pcd_start_srp_timer(dwc_otg_core_if_t * core_if)
-+{
-+ core_if->srp_timer_started = 1;
-+ DWC_TIMER_SCHEDULE(core_if->srp_timer, 6000 /* 6 secs */ );
-+}
-+
-+void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t *addr = (uint32_t *) & (core_if->core_global_regs->gotgctl);
-+ gotgctl_data_t mem;
-+ gotgctl_data_t val;
-+
-+ val.d32 = DWC_READ_REG32(addr);
-+ if (val.b.sesreq) {
-+ DWC_ERROR("Session Request Already active!\n");
-+ return;
-+ }
-+
-+ DWC_INFO("Session Request Initated\n"); //NOTICE
-+ mem.d32 = DWC_READ_REG32(addr);
-+ mem.b.sesreq = 1;
-+ DWC_WRITE_REG32(addr, mem.d32);
-+
-+ /* Start the SRP timer */
-+ dwc_otg_pcd_start_srp_timer(core_if);
-+ return;
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cil.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cil.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cil.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cil.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1464 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
-+ * $Revision: #123 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#if !defined(__DWC_CIL_H__)
-+#define __DWC_CIL_H__
-+
-+#include "dwc_list.h"
-+#include "dwc_otg_dbg.h"
-+#include "dwc_otg_regs.h"
-+
-+#include "dwc_otg_core_if.h"
-+#include "dwc_otg_adp.h"
-+
-+/**
-+ * @file
-+ * This file contains the interface to the Core Interface Layer.
-+ */
-+
-+#ifdef DWC_UTE_CFI
-+
-+#define MAX_DMA_DESCS_PER_EP 256
-+
-+/**
-+ * Enumeration for the data buffer mode
-+ */
-+typedef enum _data_buffer_mode {
-+ BM_STANDARD = 0, /* data buffer is in normal mode */
-+ BM_SG = 1, /* data buffer uses the scatter/gather mode */
-+ BM_CONCAT = 2, /* data buffer uses the concatenation mode */
-+ BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */
-+ BM_ALIGN = 4 /* data buffer is in buffer alignment mode */
-+} data_buffer_mode_e;
-+#endif //DWC_UTE_CFI
-+
-+/** Macros defined for DWC OTG HW Release version */
-+
-+#define OTG_CORE_REV_2_60a 0x4F54260A
-+#define OTG_CORE_REV_2_71a 0x4F54271A
-+#define OTG_CORE_REV_2_72a 0x4F54272A
-+#define OTG_CORE_REV_2_80a 0x4F54280A
-+#define OTG_CORE_REV_2_81a 0x4F54281A
-+#define OTG_CORE_REV_2_90a 0x4F54290A
-+#define OTG_CORE_REV_2_91a 0x4F54291A
-+#define OTG_CORE_REV_2_92a 0x4F54292A
-+#define OTG_CORE_REV_2_93a 0x4F54293A
-+#define OTG_CORE_REV_2_94a 0x4F54294A
-+#define OTG_CORE_REV_3_00a 0x4F54300A
-+
-+/**
-+ * Information for each ISOC packet.
-+ */
-+typedef struct iso_pkt_info {
-+ uint32_t offset;
-+ uint32_t length;
-+ int32_t status;
-+} iso_pkt_info_t;
-+
-+/**
-+ * The <code>dwc_ep</code> structure represents the state of a single
-+ * endpoint when acting in device mode. It contains the data items
-+ * needed for an endpoint to be activated and transfer packets.
-+ */
-+typedef struct dwc_ep {
-+ /** EP number used for register address lookup */
-+ uint8_t num;
-+ /** EP direction 0 = OUT */
-+ unsigned is_in:1;
-+ /** EP active. */
-+ unsigned active:1;
-+
-+ /**
-+ * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic
-+ * Tx FIFO. If dedicated Tx FIFOs are enabled Tx FIFO # FOR IN EPs*/
-+ unsigned tx_fifo_num:4;
-+ /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
-+ unsigned type:2;
-+#define DWC_OTG_EP_TYPE_CONTROL 0
-+#define DWC_OTG_EP_TYPE_ISOC 1
-+#define DWC_OTG_EP_TYPE_BULK 2
-+#define DWC_OTG_EP_TYPE_INTR 3
-+
-+ /** DATA start PID for INTR and BULK EP */
-+ unsigned data_pid_start:1;
-+ /** Frame (even/odd) for ISOC EP */
-+ unsigned even_odd_frame:1;
-+ /** Max Packet bytes */
-+ unsigned maxpacket:11;
-+
-+ /** Max Transfer size */
-+ uint32_t maxxfer;
-+
-+ /** @name Transfer state */
-+ /** @{ */
-+
-+ /**
-+ * Pointer to the beginning of the transfer buffer -- do not modify
-+ * during transfer.
-+ */
-+
-+ dwc_dma_t dma_addr;
-+
-+ dwc_dma_t dma_desc_addr;
-+ dwc_otg_dev_dma_desc_t *desc_addr;
-+
-+ uint8_t *start_xfer_buff;
-+ /** pointer to the transfer buffer */
-+ uint8_t *xfer_buff;
-+ /** Number of bytes to transfer */
-+ unsigned xfer_len:19;
-+ /** Number of bytes transferred. */
-+ unsigned xfer_count:19;
-+ /** Sent ZLP */
-+ unsigned sent_zlp:1;
-+ /** Total len for control transfer */
-+ unsigned total_len:19;
-+
-+ /** stall clear flag */
-+ unsigned stall_clear_flag:1;
-+
-+ /** SETUP pkt cnt rollover flag for EP0 out*/
-+ unsigned stp_rollover;
-+
-+#ifdef DWC_UTE_CFI
-+ /* The buffer mode */
-+ data_buffer_mode_e buff_mode;
-+
-+ /* The chain of DMA descriptors.
-+ * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
-+ */
-+ dwc_otg_dma_desc_t *descs;
-+
-+ /* The DMA address of the descriptors chain start */
-+ dma_addr_t descs_dma_addr;
-+ /** This variable stores the length of the last enqueued request */
-+ uint32_t cfi_req_len;
-+#endif //DWC_UTE_CFI
-+
-+/** Max DMA Descriptor count for any EP */
-+#define MAX_DMA_DESC_CNT 256
-+ /** Allocated DMA Desc count */
-+ uint32_t desc_cnt;
-+
-+ /** bInterval */
-+ uint32_t bInterval;
-+ /** Next frame num to setup next ISOC transfer */
-+ uint32_t frame_num;
-+ /** Indicates SOF number overrun in DSTS */
-+ uint8_t frm_overrun;
-+
-+#ifdef DWC_UTE_PER_IO
-+ /** Next frame num for which will be setup DMA Desc */
-+ uint32_t xiso_frame_num;
-+ /** bInterval */
-+ uint32_t xiso_bInterval;
-+ /** Count of currently active transfers - shall be either 0 or 1 */
-+ int xiso_active_xfers;
-+ int xiso_queued_xfers;
-+#endif
-+#ifdef DWC_EN_ISOC
-+ /**
-+ * Variables specific for ISOC EPs
-+ *
-+ */
-+ /** DMA addresses of ISOC buffers */
-+ dwc_dma_t dma_addr0;
-+ dwc_dma_t dma_addr1;
-+
-+ dwc_dma_t iso_dma_desc_addr;
-+ dwc_otg_dev_dma_desc_t *iso_desc_addr;
-+
-+ /** pointer to the transfer buffers */
-+ uint8_t *xfer_buff0;
-+ uint8_t *xfer_buff1;
-+
-+ /** number of ISOC Buffer is processing */
-+ uint32_t proc_buf_num;
-+ /** Interval of ISOC Buffer processing */
-+ uint32_t buf_proc_intrvl;
-+ /** Data size for regular frame */
-+ uint32_t data_per_frame;
-+
-+ /* todo - pattern data support is to be implemented in the future */
-+ /** Data size for pattern frame */
-+ uint32_t data_pattern_frame;
-+ /** Frame number of pattern data */
-+ uint32_t sync_frame;
-+
-+ /** bInterval */
-+ uint32_t bInterval;
-+ /** ISO Packet number per frame */
-+ uint32_t pkt_per_frm;
-+ /** Next frame num for which will be setup DMA Desc */
-+ uint32_t next_frame;
-+ /** Number of packets per buffer processing */
-+ uint32_t pkt_cnt;
-+ /** Info for all isoc packets */
-+ iso_pkt_info_t *pkt_info;
-+ /** current pkt number */
-+ uint32_t cur_pkt;
-+ /** current pkt number */
-+ uint8_t *cur_pkt_addr;
-+ /** current pkt number */
-+ uint32_t cur_pkt_dma_addr;
-+#endif /* DWC_EN_ISOC */
-+
-+/** @} */
-+} dwc_ep_t;
-+
-+/*
-+ * Reasons for halting a host channel.
-+ */
-+typedef enum dwc_otg_halt_status {
-+ DWC_OTG_HC_XFER_NO_HALT_STATUS,
-+ DWC_OTG_HC_XFER_COMPLETE,
-+ DWC_OTG_HC_XFER_URB_COMPLETE,
-+ DWC_OTG_HC_XFER_ACK,
-+ DWC_OTG_HC_XFER_NAK,
-+ DWC_OTG_HC_XFER_NYET,
-+ DWC_OTG_HC_XFER_STALL,
-+ DWC_OTG_HC_XFER_XACT_ERR,
-+ DWC_OTG_HC_XFER_FRAME_OVERRUN,
-+ DWC_OTG_HC_XFER_BABBLE_ERR,
-+ DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
-+ DWC_OTG_HC_XFER_AHB_ERR,
-+ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
-+ DWC_OTG_HC_XFER_URB_DEQUEUE
-+} dwc_otg_halt_status_e;
-+
-+/**
-+ * Host channel descriptor. This structure represents the state of a single
-+ * host channel when acting in host mode. It contains the data items needed to
-+ * transfer packets to an endpoint via a host channel.
-+ */
-+typedef struct dwc_hc {
-+ /** Host channel number used for register address lookup */
-+ uint8_t hc_num;
-+
-+ /** Device to access */
-+ unsigned dev_addr:7;
-+
-+ /** EP to access */
-+ unsigned ep_num:4;
-+
-+ /** EP direction. 0: OUT, 1: IN */
-+ unsigned ep_is_in:1;
-+
-+ /**
-+ * EP speed.
-+ * One of the following values:
-+ * - DWC_OTG_EP_SPEED_LOW
-+ * - DWC_OTG_EP_SPEED_FULL
-+ * - DWC_OTG_EP_SPEED_HIGH
-+ */
-+ unsigned speed:2;
-+#define DWC_OTG_EP_SPEED_LOW 0
-+#define DWC_OTG_EP_SPEED_FULL 1
-+#define DWC_OTG_EP_SPEED_HIGH 2
-+
-+ /**
-+ * Endpoint type.
-+ * One of the following values:
-+ * - DWC_OTG_EP_TYPE_CONTROL: 0
-+ * - DWC_OTG_EP_TYPE_ISOC: 1
-+ * - DWC_OTG_EP_TYPE_BULK: 2
-+ * - DWC_OTG_EP_TYPE_INTR: 3
-+ */
-+ unsigned ep_type:2;
-+
-+ /** Max packet size in bytes */
-+ unsigned max_packet:11;
-+
-+ /**
-+ * PID for initial transaction.
-+ * 0: DATA0,<br>
-+ * 1: DATA2,<br>
-+ * 2: DATA1,<br>
-+ * 3: MDATA (non-Control EP),
-+ * SETUP (Control EP)
-+ */
-+ unsigned data_pid_start:2;
-+#define DWC_OTG_HC_PID_DATA0 0
-+#define DWC_OTG_HC_PID_DATA2 1
-+#define DWC_OTG_HC_PID_DATA1 2
-+#define DWC_OTG_HC_PID_MDATA 3
-+#define DWC_OTG_HC_PID_SETUP 3
-+
-+ /** Number of periodic transactions per (micro)frame */
-+ unsigned multi_count:2;
-+
-+ /** @name Transfer State */
-+ /** @{ */
-+
-+ /** Pointer to the current transfer buffer position. */
-+ uint8_t *xfer_buff;
-+ /**
-+ * In Buffer DMA mode this buffer will be used
-+ * if xfer_buff is not DWORD aligned.
-+ */
-+ dwc_dma_t align_buff;
-+ /** Total number of bytes to transfer. */
-+ uint32_t xfer_len;
-+ /** Number of bytes transferred so far. */
-+ uint32_t xfer_count;
-+ /** Packet count at start of transfer.*/
-+ uint16_t start_pkt_count;
-+
-+ /**
-+ * Flag to indicate whether the transfer has been started. Set to 1 if
-+ * it has been started, 0 otherwise.
-+ */
-+ uint8_t xfer_started;
-+
-+ /**
-+ * Set to 1 to indicate that a PING request should be issued on this
-+ * channel. If 0, process normally.
-+ */
-+ uint8_t do_ping;
-+
-+ /**
-+ * Set to 1 to indicate that the error count for this transaction is
-+ * non-zero. Set to 0 if the error count is 0.
-+ */
-+ uint8_t error_state;
-+
-+ /**
-+ * Set to 1 to indicate that this channel should be halted the next
-+ * time a request is queued for the channel. This is necessary in
-+ * slave mode if no request queue space is available when an attempt
-+ * is made to halt the channel.
-+ */
-+ uint8_t halt_on_queue;
-+
-+ /**
-+ * Set to 1 if the host channel has been halted, but the core is not
-+ * finished flushing queued requests. Otherwise 0.
-+ */
-+ uint8_t halt_pending;
-+
-+ /**
-+ * Reason for halting the host channel.
-+ */
-+ dwc_otg_halt_status_e halt_status;
-+
-+ /*
-+ * Split settings for the host channel
-+ */
-+ uint8_t do_split; /**< Enable split for the channel */
-+ uint8_t complete_split; /**< Enable complete split */
-+ uint8_t hub_addr; /**< Address of high speed hub */
-+
-+ uint8_t port_addr; /**< Port of the low/full speed device */
-+ /** Split transaction position
-+ * One of the following values:
-+ * - DWC_HCSPLIT_XACTPOS_MID
-+ * - DWC_HCSPLIT_XACTPOS_BEGIN
-+ * - DWC_HCSPLIT_XACTPOS_END
-+ * - DWC_HCSPLIT_XACTPOS_ALL */
-+ uint8_t xact_pos;
-+
-+ /** Set when the host channel does a short read. */
-+ uint8_t short_read;
-+
-+ /**
-+ * Number of requests issued for this channel since it was assigned to
-+ * the current transfer (not counting PINGs).
-+ */
-+ uint8_t requests;
-+
-+ /**
-+ * Queue Head for the transfer being processed by this channel.
-+ */
-+ struct dwc_otg_qh *qh;
-+
-+ /** @} */
-+
-+ /** Entry in list of host channels. */
-+ DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
-+
-+ /** @name Descriptor DMA support */
-+ /** @{ */
-+
-+ /** Number of Transfer Descriptors */
-+ uint16_t ntd;
-+
-+ /** Descriptor List DMA address */
-+ dwc_dma_t desc_list_addr;
-+
-+ /** Scheduling micro-frame bitmap. */
-+ uint8_t schinfo;
-+
-+ /** @} */
-+} dwc_hc_t;
-+
-+/**
-+ * The following parameters may be specified when starting the module. These
-+ * parameters define how the DWC_otg controller should be configured.
-+ */
-+typedef struct dwc_otg_core_params {
-+ int32_t opt;
-+
-+ /**
-+ * Specifies the OTG capabilities. The driver will automatically
-+ * detect the value for this parameter if none is specified.
-+ * 0 - HNP and SRP capable (default)
-+ * 1 - SRP Only capable
-+ * 2 - No HNP/SRP capable
-+ */
-+ int32_t otg_cap;
-+
-+ /**
-+ * Specifies whether to use slave or DMA mode for accessing the data
-+ * FIFOs. The driver will automatically detect the value for this
-+ * parameter if none is specified.
-+ * 0 - Slave
-+ * 1 - DMA (default, if available)
-+ */
-+ int32_t dma_enable;
-+
-+ /**
-+ * When DMA mode is enabled specifies whether to use address DMA or DMA
-+ * Descriptor mode for accessing the data FIFOs in device mode. The driver
-+ * will automatically detect the value for this if none is specified.
-+ * 0 - address DMA
-+ * 1 - DMA Descriptor(default, if available)
-+ */
-+ int32_t dma_desc_enable;
-+ /** The DMA Burst size (applicable only for External DMA
-+ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
-+ */
-+ int32_t dma_burst_size; /* Translate this to GAHBCFG values */
-+
-+ /**
-+ * Specifies the maximum speed of operation in host and device mode.
-+ * The actual speed depends on the speed of the attached device and
-+ * the value of phy_type. The actual speed depends on the speed of the
-+ * attached device.
-+ * 0 - High Speed (default)
-+ * 1 - Full Speed
-+ */
-+ int32_t speed;
-+ /** Specifies whether low power mode is supported when attached
-+ * to a Full Speed or Low Speed device in host mode.
-+ * 0 - Don't support low power mode (default)
-+ * 1 - Support low power mode
-+ */
-+ int32_t host_support_fs_ls_low_power;
-+
-+ /** Specifies the PHY clock rate in low power mode when connected to a
-+ * Low Speed device in host mode. This parameter is applicable only if
-+ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
-+ * then defaults to 6 MHZ otherwise 48 MHZ.
-+ *
-+ * 0 - 48 MHz
-+ * 1 - 6 MHz
-+ */
-+ int32_t host_ls_low_power_phy_clk;
-+
-+ /**
-+ * 0 - Use cC FIFO size parameters
-+ * 1 - Allow dynamic FIFO sizing (default)
-+ */
-+ int32_t enable_dynamic_fifo;
-+
-+ /** Total number of 4-byte words in the data FIFO memory. This
-+ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
-+ * Tx FIFOs.
-+ * 32 to 32768 (default 8192)
-+ * Note: The total FIFO memory depth in the FPGA configuration is 8192.
-+ */
-+ int32_t data_fifo_size;
-+
-+ /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
-+ * FIFO sizing is enabled.
-+ * 16 to 32768 (default 1064)
-+ */
-+ int32_t dev_rx_fifo_size;
-+
-+ /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
-+ * when dynamic FIFO sizing is enabled.
-+ * 16 to 32768 (default 1024)
-+ */
-+ int32_t dev_nperio_tx_fifo_size;
-+
-+ /** Number of 4-byte words in each of the periodic Tx FIFOs in device
-+ * mode when dynamic FIFO sizing is enabled.
-+ * 4 to 768 (default 256)
-+ */
-+ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
-+
-+ /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
-+ * FIFO sizing is enabled.
-+ * 16 to 32768 (default 1024)
-+ */
-+ int32_t host_rx_fifo_size;
-+
-+ /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
-+ * when Dynamic FIFO sizing is enabled in the core.
-+ * 16 to 32768 (default 1024)
-+ */
-+ int32_t host_nperio_tx_fifo_size;
-+
-+ /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
-+ * FIFO sizing is enabled.
-+ * 16 to 32768 (default 1024)
-+ */
-+ int32_t host_perio_tx_fifo_size;
-+
-+ /** The maximum transfer size supported in bytes.
-+ * 2047 to 65,535 (default 65,535)
-+ */
-+ int32_t max_transfer_size;
-+
-+ /** The maximum number of packets in a transfer.
-+ * 15 to 511 (default 511)
-+ */
-+ int32_t max_packet_count;
-+
-+ /** The number of host channel registers to use.
-+ * 1 to 16 (default 12)
-+ * Note: The FPGA configuration supports a maximum of 12 host channels.
-+ */
-+ int32_t host_channels;
-+
-+ /** The number of endpoints in addition to EP0 available for device
-+ * mode operations.
-+ * 1 to 15 (default 6 IN and OUT)
-+ * Note: The FPGA configuration supports a maximum of 6 IN and OUT
-+ * endpoints in addition to EP0.
-+ */
-+ int32_t dev_endpoints;
-+
-+ /**
-+ * Specifies the type of PHY interface to use. By default, the driver
-+ * will automatically detect the phy_type.
-+ *
-+ * 0 - Full Speed PHY
-+ * 1 - UTMI+ (default)
-+ * 2 - ULPI
-+ */
-+ int32_t phy_type;
-+
-+ /**
-+ * Specifies the UTMI+ Data Width. This parameter is
-+ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
-+ * PHY_TYPE, this parameter indicates the data width between
-+ * the MAC and the ULPI Wrapper.) Also, this parameter is
-+ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
-+ * to "8 and 16 bits", meaning that the core has been
-+ * configured to work at either data path width.
-+ *
-+ * 8 or 16 bits (default 16)
-+ */
-+ int32_t phy_utmi_width;
-+
-+ /**
-+ * Specifies whether the ULPI operates at double or single
-+ * data rate. This parameter is only applicable if PHY_TYPE is
-+ * ULPI.
-+ *
-+ * 0 - single data rate ULPI interface with 8 bit wide data
-+ * bus (default)
-+ * 1 - double data rate ULPI interface with 4 bit wide data
-+ * bus
-+ */
-+ int32_t phy_ulpi_ddr;
-+
-+ /**
-+ * Specifies whether to use the internal or external supply to
-+ * drive the vbus with a ULPI phy.
-+ */
-+ int32_t phy_ulpi_ext_vbus;
-+
-+ /**
-+ * Specifies whether to use the I2Cinterface for full speed PHY. This
-+ * parameter is only applicable if PHY_TYPE is FS.
-+ * 0 - No (default)
-+ * 1 - Yes
-+ */
-+ int32_t i2c_enable;
-+
-+ int32_t ulpi_fs_ls;
-+
-+ int32_t ts_dline;
-+
-+ /**
-+ * Specifies whether dedicated transmit FIFOs are
-+ * enabled for non periodic IN endpoints in device mode
-+ * 0 - No
-+ * 1 - Yes
-+ */
-+ int32_t en_multiple_tx_fifo;
-+
-+ /** Number of 4-byte words in each of the Tx FIFOs in device
-+ * mode when dynamic FIFO sizing is enabled.
-+ * 4 to 768 (default 256)
-+ */
-+ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
-+
-+ /** Thresholding enable flag-
-+ * bit 0 - enable non-ISO Tx thresholding
-+ * bit 1 - enable ISO Tx thresholding
-+ * bit 2 - enable Rx thresholding
-+ */
-+ uint32_t thr_ctl;
-+
-+ /** Thresholding length for Tx
-+ * FIFOs in 32 bit DWORDs
-+ */
-+ uint32_t tx_thr_length;
-+
-+ /** Thresholding length for Rx
-+ * FIFOs in 32 bit DWORDs
-+ */
-+ uint32_t rx_thr_length;
-+
-+ /**
-+ * Specifies whether LPM (Link Power Management) support is enabled
-+ */
-+ int32_t lpm_enable;
-+
-+ /** Per Transfer Interrupt
-+ * mode enable flag
-+ * 1 - Enabled
-+ * 0 - Disabled
-+ */
-+ int32_t pti_enable;
-+
-+ /** Multi Processor Interrupt
-+ * mode enable flag
-+ * 1 - Enabled
-+ * 0 - Disabled
-+ */
-+ int32_t mpi_enable;
-+
-+ /** IS_USB Capability
-+ * 1 - Enabled
-+ * 0 - Disabled
-+ */
-+ int32_t ic_usb_cap;
-+
-+ /** AHB Threshold Ratio
-+ * 2'b00 AHB Threshold = MAC Threshold
-+ * 2'b01 AHB Threshold = 1/2 MAC Threshold
-+ * 2'b10 AHB Threshold = 1/4 MAC Threshold
-+ * 2'b11 AHB Threshold = 1/8 MAC Threshold
-+ */
-+ int32_t ahb_thr_ratio;
-+
-+ /** ADP Support
-+ * 1 - Enabled
-+ * 0 - Disabled
-+ */
-+ int32_t adp_supp_enable;
-+
-+ /** HFIR Reload Control
-+ * 0 - The HFIR cannot be reloaded dynamically.
-+ * 1 - Allow dynamic reloading of the HFIR register during runtime.
-+ */
-+ int32_t reload_ctl;
-+
-+ /** DCFG: Enable device Out NAK
-+ * 0 - The core does not set NAK after Bulk Out transfer complete.
-+ * 1 - The core sets NAK after Bulk OUT transfer complete.
-+ */
-+ int32_t dev_out_nak;
-+
-+ /** DCFG: Enable Continue on BNA
-+ * After receiving BNA interrupt the core disables the endpoint,when the
-+ * endpoint is re-enabled by the application the core starts processing
-+ * 0 - from the DOEPDMA descriptor
-+ * 1 - from the descriptor which received the BNA.
-+ */
-+ int32_t cont_on_bna;
-+
-+ /** GAHBCFG: AHB Single Support
-+ * This bit when programmed supports SINGLE transfers for remainder
-+ * data in a transfer for DMA mode of operation.
-+ * 0 - in this case the remainder data will be sent using INCR burst size.
-+ * 1 - in this case the remainder data will be sent using SINGLE burst size.
-+ */
-+ int32_t ahb_single;
-+
-+ /** Core Power down mode
-+ * 0 - No Power Down is enabled
-+ * 1 - Reserved
-+ * 2 - Complete Power Down (Hibernation)
-+ */
-+ int32_t power_down;
-+
-+ /** OTG revision supported
-+ * 0 - OTG 1.3 revision
-+ * 1 - OTG 2.0 revision
-+ */
-+ int32_t otg_ver;
-+
-+} dwc_otg_core_params_t;
-+
-+#ifdef DEBUG
-+struct dwc_otg_core_if;
-+typedef struct hc_xfer_info {
-+ struct dwc_otg_core_if *core_if;
-+ dwc_hc_t *hc;
-+} hc_xfer_info_t;
-+#endif
-+
-+typedef struct ep_xfer_info {
-+ struct dwc_otg_core_if *core_if;
-+ dwc_ep_t *ep;
-+ uint8_t state;
-+} ep_xfer_info_t;
-+/*
-+ * Device States
-+ */
-+typedef enum dwc_otg_lx_state {
-+ /** On state */
-+ DWC_OTG_L0,
-+ /** LPM sleep state*/
-+ DWC_OTG_L1,
-+ /** USB suspend state*/
-+ DWC_OTG_L2,
-+ /** Off state*/
-+ DWC_OTG_L3
-+} dwc_otg_lx_state_e;
-+
-+struct dwc_otg_global_regs_backup {
-+ uint32_t gotgctl_local;
-+ uint32_t gintmsk_local;
-+ uint32_t gahbcfg_local;
-+ uint32_t gusbcfg_local;
-+ uint32_t grxfsiz_local;
-+ uint32_t gnptxfsiz_local;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ uint32_t glpmcfg_local;
-+#endif
-+ uint32_t gi2cctl_local;
-+ uint32_t hptxfsiz_local;
-+ uint32_t pcgcctl_local;
-+ uint32_t gdfifocfg_local;
-+ uint32_t dtxfsiz_local[MAX_EPS_CHANNELS];
-+ uint32_t gpwrdn_local;
-+ uint32_t xhib_pcgcctl;
-+ uint32_t xhib_gpwrdn;
-+};
-+
-+struct dwc_otg_host_regs_backup {
-+ uint32_t hcfg_local;
-+ uint32_t haintmsk_local;
-+ uint32_t hcintmsk_local[MAX_EPS_CHANNELS];
-+ uint32_t hprt0_local;
-+ uint32_t hfir_local;
-+};
-+
-+struct dwc_otg_dev_regs_backup {
-+ uint32_t dcfg;
-+ uint32_t dctl;
-+ uint32_t daintmsk;
-+ uint32_t diepmsk;
-+ uint32_t doepmsk;
-+ uint32_t diepctl[MAX_EPS_CHANNELS];
-+ uint32_t dieptsiz[MAX_EPS_CHANNELS];
-+ uint32_t diepdma[MAX_EPS_CHANNELS];
-+};
-+/**
-+ * The <code>dwc_otg_core_if</code> structure contains information needed to manage
-+ * the DWC_otg controller acting in either host or device mode. It
-+ * represents the programming view of the controller as a whole.
-+ */
-+struct dwc_otg_core_if {
-+ /** Parameters that define how the core should be configured.*/
-+ dwc_otg_core_params_t *core_params;
-+
-+ /** Core Global registers starting at offset 000h. */
-+ dwc_otg_core_global_regs_t *core_global_regs;
-+
-+ /** Device-specific information */
-+ dwc_otg_dev_if_t *dev_if;
-+ /** Host-specific information */
-+ dwc_otg_host_if_t *host_if;
-+
-+ /** Value from SNPSID register */
-+ uint32_t snpsid;
-+
-+ /*
-+ * Set to 1 if the core PHY interface bits in USBCFG have been
-+ * initialized.
-+ */
-+ uint8_t phy_init_done;
-+
-+ /*
-+ * SRP Success flag, set by srp success interrupt in FS I2C mode
-+ */
-+ uint8_t srp_success;
-+ uint8_t srp_timer_started;
-+ /** Timer for SRP. If it expires before SRP is successful
-+ * clear the SRP. */
-+ dwc_timer_t *srp_timer;
-+
-+#ifdef DWC_DEV_SRPCAP
-+ /* This timer is needed to power on the hibernated host core if SRP is not
-+ * initiated on connected SRP capable device for limited period of time
-+ */
-+ uint8_t pwron_timer_started;
-+ dwc_timer_t *pwron_timer;
-+#endif
-+ /* Common configuration information */
-+ /** Power and Clock Gating Control Register */
-+ volatile uint32_t *pcgcctl;
-+#define DWC_OTG_PCGCCTL_OFFSET 0xE00
-+
-+ /** Push/pop addresses for endpoints or host channels.*/
-+ uint32_t *data_fifo[MAX_EPS_CHANNELS];
-+#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
-+#define DWC_OTG_DATA_FIFO_SIZE 0x1000
-+
-+ /** Total RAM for FIFOs (Bytes) */
-+ uint16_t total_fifo_size;
-+ /** Size of Rx FIFO (Bytes) */
-+ uint16_t rx_fifo_size;
-+ /** Size of Non-periodic Tx FIFO (Bytes) */
-+ uint16_t nperio_tx_fifo_size;
-+
-+ /** 1 if DMA is enabled, 0 otherwise. */
-+ uint8_t dma_enable;
-+
-+ /** 1 if DMA descriptor is enabled, 0 otherwise. */
-+ uint8_t dma_desc_enable;
-+
-+ /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */
-+ uint8_t pti_enh_enable;
-+
-+ /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */
-+ uint8_t multiproc_int_enable;
-+
-+ /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
-+ uint8_t en_multiple_tx_fifo;
-+
-+ /** Set to 1 if multiple packets of a high-bandwidth transfer is in
-+ * process of being queued */
-+ uint8_t queuing_high_bandwidth;
-+
-+ /** Hardware Configuration -- stored here for convenience.*/
-+ hwcfg1_data_t hwcfg1;
-+ hwcfg2_data_t hwcfg2;
-+ hwcfg3_data_t hwcfg3;
-+ hwcfg4_data_t hwcfg4;
-+ fifosize_data_t hptxfsiz;
-+
-+ /** Host and Device Configuration -- stored here for convenience.*/
-+ hcfg_data_t hcfg;
-+ dcfg_data_t dcfg;
-+
-+ /** The operational State, during transations
-+ * (a_host>>a_peripherial and b_device=>b_host) this may not
-+ * match the core but allows the software to determine
-+ * transitions.
-+ */
-+ uint8_t op_state;
-+
-+ /**
-+ * Set to 1 if the HCD needs to be restarted on a session request
-+ * interrupt. This is required if no connector ID status change has
-+ * occurred since the HCD was last disconnected.
-+ */
-+ uint8_t restart_hcd_on_session_req;
-+
-+ /** HCD callbacks */
-+ /** A-Device is a_host */
-+#define A_HOST (1)
-+ /** A-Device is a_suspend */
-+#define A_SUSPEND (2)
-+ /** A-Device is a_peripherial */
-+#define A_PERIPHERAL (3)
-+ /** B-Device is operating as a Peripheral. */
-+#define B_PERIPHERAL (4)
-+ /** B-Device is operating as a Host. */
-+#define B_HOST (5)
-+
-+ /** HCD callbacks */
-+ struct dwc_otg_cil_callbacks *hcd_cb;
-+ /** PCD callbacks */
-+ struct dwc_otg_cil_callbacks *pcd_cb;
-+
-+ /** Device mode Periodic Tx FIFO Mask */
-+ uint32_t p_tx_msk;
-+ /** Device mode Periodic Tx FIFO Mask */
-+ uint32_t tx_msk;
-+
-+ /** Workqueue object used for handling several interrupts */
-+ dwc_workq_t *wq_otg;
-+
-+ /** Timer object used for handling "Wakeup Detected" Interrupt */
-+ dwc_timer_t *wkp_timer;
-+ /** This arrays used for debug purposes for DEV OUT NAK enhancement */
-+ uint32_t start_doeptsiz_val[MAX_EPS_CHANNELS];
-+ ep_xfer_info_t ep_xfer_info[MAX_EPS_CHANNELS];
-+ dwc_timer_t *ep_xfer_timer[MAX_EPS_CHANNELS];
-+#ifdef DEBUG
-+ uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
-+
-+ hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
-+ dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
-+
-+ uint32_t hfnum_7_samples;
-+ uint64_t hfnum_7_frrem_accum;
-+ uint32_t hfnum_0_samples;
-+ uint64_t hfnum_0_frrem_accum;
-+ uint32_t hfnum_other_samples;
-+ uint64_t hfnum_other_frrem_accum;
-+#endif
-+
-+#ifdef DWC_UTE_CFI
-+ uint16_t pwron_rxfsiz;
-+ uint16_t pwron_gnptxfsiz;
-+ uint16_t pwron_txfsiz[15];
-+
-+ uint16_t init_rxfsiz;
-+ uint16_t init_gnptxfsiz;
-+ uint16_t init_txfsiz[15];
-+#endif
-+
-+ /** Lx state of device */
-+ dwc_otg_lx_state_e lx_state;
-+
-+ /** Saved Core Global registers */
-+ struct dwc_otg_global_regs_backup *gr_backup;
-+ /** Saved Host registers */
-+ struct dwc_otg_host_regs_backup *hr_backup;
-+ /** Saved Device registers */
-+ struct dwc_otg_dev_regs_backup *dr_backup;
-+
-+ /** Power Down Enable */
-+ uint32_t power_down;
-+
-+ /** ADP support Enable */
-+ uint32_t adp_enable;
-+
-+ /** ADP structure object */
-+ dwc_otg_adp_t adp;
-+
-+ /** hibernation/suspend flag */
-+ int hibernation_suspend;
-+
-+ /** Device mode extended hibernation flag */
-+ int xhib;
-+
-+ /** OTG revision supported */
-+ uint32_t otg_ver;
-+
-+ /** OTG status flag used for HNP polling */
-+ uint8_t otg_sts;
-+
-+ /** Pointer to either hcd->lock or pcd->lock */
-+ dwc_spinlock_t *lock;
-+
-+ /** Start predict NextEP based on Learning Queue if equal 1,
-+ * also used as counter of disabled NP IN EP's */
-+ uint8_t start_predict;
-+
-+ /** NextEp sequence, including EP0: nextep_seq[] = EP if non-periodic and
-+ * active, 0xff otherwise */
-+ uint8_t nextep_seq[MAX_EPS_CHANNELS];
-+
-+ /** Index of fisrt EP in nextep_seq array which should be re-enabled **/
-+ uint8_t first_in_nextep_seq;
-+
-+ /** Frame number while entering to ISR - needed for ISOCs **/
-+ uint32_t frame_num;
-+
-+};
-+
-+#ifdef DEBUG
-+/*
-+ * This function is called when transfer is timed out.
-+ */
-+extern void hc_xfer_timeout(void *ptr);
-+#endif
-+
-+/*
-+ * This function is called when transfer is timed out on endpoint.
-+ */
-+extern void ep_xfer_timeout(void *ptr);
-+
-+/*
-+ * The following functions are functions for works
-+ * using during handling some interrupts
-+ */
-+extern void w_conn_id_status_change(void *p);
-+
-+extern void w_wakeup_detected(void *p);
-+
-+/** Saves global register values into system memory. */
-+extern int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if);
-+/** Saves device register values into system memory. */
-+extern int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if);
-+/** Saves host register values into system memory. */
-+extern int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if);
-+/** Restore global register values. */
-+extern int dwc_otg_restore_global_regs(dwc_otg_core_if_t * core_if);
-+/** Restore host register values. */
-+extern int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset);
-+/** Restore device register values. */
-+extern int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if,
-+ int rem_wakeup);
-+extern int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if);
-+extern int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode,
-+ int is_host);
-+
-+extern int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
-+ int restore_mode, int reset);
-+extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
-+ int rem_wakeup, int reset);
-+
-+/*
-+ * The following functions support initialization of the CIL driver component
-+ * and the DWC_otg controller.
-+ */
-+extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
-+
-+/** @name Device CIL Functions
-+ * The following functions support managing the DWC_otg controller in device
-+ * mode.
-+ */
-+/**@{*/
-+extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
-+ uint32_t * _dest);
-+extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
-+extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
-+extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
-+extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
-+ dwc_ep_t * _ep);
-+extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
-+ dwc_ep_t * _ep);
-+extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
-+ dwc_ep_t * _ep);
-+extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
-+ dwc_ep_t * _ep);
-+extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
-+ dwc_ep_t * _ep, int _dma);
-+extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
-+extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
-+ dwc_ep_t * _ep);
-+extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
-+
-+#ifdef DWC_EN_ISOC
-+extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * ep);
-+extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * ep);
-+#endif /* DWC_EN_ISOC */
-+/**@}*/
-+
-+/** @name Host CIL Functions
-+ * The following functions support managing the DWC_otg controller in host
-+ * mode.
-+ */
-+/**@{*/
-+extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
-+extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
-+ dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
-+extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
-+extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
-+ dwc_hc_t * _hc);
-+extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
-+ dwc_hc_t * _hc);
-+extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
-+extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
-+ dwc_hc_t * _hc);
-+extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
-+
-+extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if,
-+ dwc_hc_t * hc);
-+
-+extern uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if);
-+
-+/* Macro used to clear one channel interrupt */
-+#define clear_hc_int(_hc_regs_, _intr_) \
-+do { \
-+ hcint_data_t hcint_clear = {.d32 = 0}; \
-+ hcint_clear.b._intr_ = 1; \
-+ DWC_WRITE_REG32(&(_hc_regs_)->hcint, hcint_clear.d32); \
-+} while (0)
-+
-+/*
-+ * Macro used to disable one channel interrupt. Channel interrupts are
-+ * disabled when the channel is halted or released by the interrupt handler.
-+ * There is no need to handle further interrupts of that type until the
-+ * channel is re-assigned. In fact, subsequent handling may cause crashes
-+ * because the channel structures are cleaned up when the channel is released.
-+ */
-+#define disable_hc_int(_hc_regs_, _intr_) \
-+do { \
-+ hcintmsk_data_t hcintmsk = {.d32 = 0}; \
-+ hcintmsk.b._intr_ = 1; \
-+ DWC_MODIFY_REG32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
-+} while (0)
-+
-+/**
-+ * This function Reads HPRT0 in preparation to modify. It keeps the
-+ * WC bits 0 so that if they are read as 1, they won't clear when you
-+ * write it back
-+ */
-+static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
-+{
-+ hprt0_data_t hprt0;
-+ hprt0.d32 = DWC_READ_REG32(_core_if->host_if->hprt0);
-+ hprt0.b.prtena = 0;
-+ hprt0.b.prtconndet = 0;
-+ hprt0.b.prtenchng = 0;
-+ hprt0.b.prtovrcurrchng = 0;
-+ return hprt0.d32;
-+}
-+
-+/**@}*/
-+
-+/** @name Common CIL Functions
-+ * The following functions support managing the DWC_otg controller in either
-+ * device or host mode.
-+ */
-+/**@{*/
-+
-+extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
-+ uint8_t * dest, uint16_t bytes);
-+
-+extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
-+extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
-+
-+/**
-+ * This function returns the Core Interrupt register.
-+ */
-+static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
-+{
-+ return (DWC_READ_REG32(&core_if->core_global_regs->gintsts) &
-+ DWC_READ_REG32(&core_if->core_global_regs->gintmsk));
-+}
-+
-+/**
-+ * This function returns the OTG Interrupt register.
-+ */
-+static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
-+{
-+ return (DWC_READ_REG32(&core_if->core_global_regs->gotgint));
-+}
-+
-+/**
-+ * This function reads the Device All Endpoints Interrupt register and
-+ * returns the IN endpoint interrupt bits.
-+ */
-+static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
-+ core_if)
-+{
-+
-+ uint32_t v;
-+
-+ if (core_if->multiproc_int_enable) {
-+ v = DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->deachint) &
-+ DWC_READ_REG32(&core_if->
-+ dev_if->dev_global_regs->deachintmsk);
-+ } else {
-+ v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
-+ }
-+ return (v & 0xffff);
-+}
-+
-+/**
-+ * This function reads the Device All Endpoints Interrupt register and
-+ * returns the OUT endpoint interrupt bits.
-+ */
-+static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
-+ core_if)
-+{
-+ uint32_t v;
-+
-+ if (core_if->multiproc_int_enable) {
-+ v = DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->deachint) &
-+ DWC_READ_REG32(&core_if->
-+ dev_if->dev_global_regs->deachintmsk);
-+ } else {
-+ v = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daint) &
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
-+ }
-+
-+ return ((v & 0xffff0000) >> 16);
-+}
-+
-+/**
-+ * This function returns the Device IN EP Interrupt register
-+ */
-+static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * ep)
-+{
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ uint32_t v, msk, emp;
-+
-+ if (core_if->multiproc_int_enable) {
-+ msk =
-+ DWC_READ_REG32(&dev_if->
-+ dev_global_regs->diepeachintmsk[ep->num]);
-+ emp =
-+ DWC_READ_REG32(&dev_if->
-+ dev_global_regs->dtknqr4_fifoemptymsk);
-+ msk |= ((emp >> ep->num) & 0x1) << 7;
-+ v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
-+ } else {
-+ msk = DWC_READ_REG32(&dev_if->dev_global_regs->diepmsk);
-+ emp =
-+ DWC_READ_REG32(&dev_if->
-+ dev_global_regs->dtknqr4_fifoemptymsk);
-+ msk |= ((emp >> ep->num) & 0x1) << 7;
-+ v = DWC_READ_REG32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
-+ }
-+
-+ return v;
-+}
-+
-+/**
-+ * This function returns the Device OUT EP Interrupt register
-+ */
-+static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
-+ _core_if, dwc_ep_t * _ep)
-+{
-+ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
-+ uint32_t v;
-+ doepmsk_data_t msk = {.d32 = 0 };
-+
-+ if (_core_if->multiproc_int_enable) {
-+ msk.d32 =
-+ DWC_READ_REG32(&dev_if->
-+ dev_global_regs->doepeachintmsk[_ep->num]);
-+ if (_core_if->pti_enh_enable) {
-+ msk.b.pktdrpsts = 1;
-+ }
-+ v = DWC_READ_REG32(&dev_if->
-+ out_ep_regs[_ep->num]->doepint) & msk.d32;
-+ } else {
-+ msk.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->doepmsk);
-+ if (_core_if->pti_enh_enable) {
-+ msk.b.pktdrpsts = 1;
-+ }
-+ v = DWC_READ_REG32(&dev_if->
-+ out_ep_regs[_ep->num]->doepint) & msk.d32;
-+ }
-+ return v;
-+}
-+
-+/**
-+ * This function returns the Host All Channel Interrupt register
-+ */
-+static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
-+ _core_if)
-+{
-+ return (DWC_READ_REG32(&_core_if->host_if->host_global_regs->haint));
-+}
-+
-+static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
-+ _core_if, dwc_hc_t * _hc)
-+{
-+ return (DWC_READ_REG32
-+ (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
-+}
-+
-+/**
-+ * This function returns the mode of the operation, host or device.
-+ *
-+ * @return 0 - Device Mode, 1 - Host Mode
-+ */
-+static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
-+{
-+ return (DWC_READ_REG32(&_core_if->core_global_regs->gintsts) & 0x1);
-+}
-+
-+/**@}*/
-+
-+/**
-+ * DWC_otg CIL callback structure. This structure allows the HCD and
-+ * PCD to register functions used for starting and stopping the PCD
-+ * and HCD for role change on for a DRD.
-+ */
-+typedef struct dwc_otg_cil_callbacks {
-+ /** Start function for role change */
-+ int (*start) (void *_p);
-+ /** Stop Function for role change */
-+ int (*stop) (void *_p);
-+ /** Disconnect Function for role change */
-+ int (*disconnect) (void *_p);
-+ /** Resume/Remote wakeup Function */
-+ int (*resume_wakeup) (void *_p);
-+ /** Suspend function */
-+ int (*suspend) (void *_p);
-+ /** Session Start (SRP) */
-+ int (*session_start) (void *_p);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ /** Sleep (switch to L0 state) */
-+ int (*sleep) (void *_p);
-+#endif
-+ /** Pointer passed to start() and stop() */
-+ void *p;
-+} dwc_otg_cil_callbacks_t;
-+
-+extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
-+ dwc_otg_cil_callbacks_t * _cb,
-+ void *_p);
-+extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
-+ dwc_otg_cil_callbacks_t * _cb,
-+ void *_p);
-+
-+void dwc_otg_initiate_srp(dwc_otg_core_if_t * core_if);
-+
-+//////////////////////////////////////////////////////////////////////
-+/** Start the HCD. Helper function for using the HCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_hcd_start(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->hcd_cb && core_if->hcd_cb->start) {
-+ core_if->hcd_cb->start(core_if->hcd_cb->p);
-+ }
-+}
-+
-+/** Stop the HCD. Helper function for using the HCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_hcd_stop(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->hcd_cb && core_if->hcd_cb->stop) {
-+ core_if->hcd_cb->stop(core_if->hcd_cb->p);
-+ }
-+}
-+
-+/** Disconnect the HCD. Helper function for using the HCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_hcd_disconnect(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
-+ core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
-+ }
-+}
-+
-+/** Inform the HCD the a New Session has begun. Helper function for
-+ * using the HCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_hcd_session_start(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
-+ core_if->hcd_cb->session_start(core_if->hcd_cb->p);
-+ }
-+}
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+/**
-+ * Inform the HCD about LPM sleep.
-+ * Helper function for using the HCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_hcd_sleep(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
-+ core_if->hcd_cb->sleep(core_if->hcd_cb->p);
-+ }
-+}
-+#endif
-+
-+/** Resume the HCD. Helper function for using the HCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_hcd_resume(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
-+ core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
-+ }
-+}
-+
-+/** Start the PCD. Helper function for using the PCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_pcd_start(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->pcd_cb && core_if->pcd_cb->start) {
-+ core_if->pcd_cb->start(core_if->pcd_cb->p);
-+ }
-+}
-+
-+/** Stop the PCD. Helper function for using the PCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_pcd_stop(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->pcd_cb && core_if->pcd_cb->stop) {
-+ core_if->pcd_cb->stop(core_if->pcd_cb->p);
-+ }
-+}
-+
-+/** Suspend the PCD. Helper function for using the PCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_pcd_suspend(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
-+ core_if->pcd_cb->suspend(core_if->pcd_cb->p);
-+ }
-+}
-+
-+/** Resume the PCD. Helper function for using the PCD callbacks.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static inline void cil_pcd_resume(dwc_otg_core_if_t * core_if)
-+{
-+ if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
-+ core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
-+ }
-+}
-+
-+//////////////////////////////////////////////////////////////////////
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1588 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
-+ * $Revision: #32 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+/** @file
-+ *
-+ * The Core Interface Layer provides basic services for accessing and
-+ * managing the DWC_otg hardware. These services are used by both the
-+ * Host Controller Driver and the Peripheral Controller Driver.
-+ *
-+ * This file contains the Common Interrupt handlers.
-+ */
-+#include "dwc_os.h"
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_cil.h"
-+#include "dwc_otg_driver.h"
-+#include "dwc_otg_pcd.h"
-+#include "dwc_otg_hcd.h"
-+#include "dwc_otg_mphi_fix.h"
-+
-+#ifdef DEBUG
-+inline const char *op_state_str(dwc_otg_core_if_t * core_if)
-+{
-+ return (core_if->op_state == A_HOST ? "a_host" :
-+ (core_if->op_state == A_SUSPEND ? "a_suspend" :
-+ (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
-+ (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
-+ (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
-+}
-+#endif
-+
-+/** This function will log a debug message
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gintsts_data_t gintsts;
-+ DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
-+ dwc_otg_mode(core_if) ? "Host" : "Device");
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.modemismatch = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+ return 1;
-+}
-+
-+/**
-+ * This function handles the OTG Interrupts. It reads the OTG
-+ * Interrupt Register (GOTGINT) to determine what interrupt has
-+ * occurred.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ gotgint_data_t gotgint;
-+ gotgctl_data_t gotgctl;
-+ gintmsk_data_t gintmsk;
-+ gpwrdn_data_t gpwrdn;
-+
-+ gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
-+ gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
-+ DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
-+ op_state_str(core_if));
-+
-+ if (gotgint.b.sesenddet) {
-+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
-+ "Session End Detected++ (%s)\n",
-+ op_state_str(core_if));
-+ gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
-+
-+ if (core_if->op_state == B_HOST) {
-+ cil_pcd_start(core_if);
-+ core_if->op_state = B_PERIPHERAL;
-+ } else {
-+ /* If not B_HOST and Device HNP still set. HNP
-+ * Did not succeed!*/
-+ if (gotgctl.b.devhnpen) {
-+ DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
-+ __DWC_ERROR("Device Not Connected/Responding!\n");
-+ }
-+
-+ /* If Session End Detected the B-Cable has
-+ * been disconnected. */
-+ /* Reset PCD and Gadget driver to a
-+ * clean state. */
-+ core_if->lx_state = DWC_OTG_L0;
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_pcd_stop(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+
-+ if (core_if->adp_enable) {
-+ if (core_if->power_down == 2) {
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->
-+ gpwrdn, gpwrdn.d32, 0);
-+ }
-+
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+
-+ dwc_otg_adp_sense_start(core_if);
-+ }
-+ }
-+
-+ gotgctl.d32 = 0;
-+ gotgctl.b.devhnpen = 1;
-+ DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
-+ }
-+ if (gotgint.b.sesreqsucstschng) {
-+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
-+ "Session Reqeust Success Status Change++\n");
-+ gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
-+ if (gotgctl.b.sesreqscs) {
-+
-+ if ((core_if->core_params->phy_type ==
-+ DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
-+ core_if->srp_success = 1;
-+ } else {
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_pcd_resume(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ /* Clear Session Request */
-+ gotgctl.d32 = 0;
-+ gotgctl.b.sesreq = 1;
-+ DWC_MODIFY_REG32(&global_regs->gotgctl,
-+ gotgctl.d32, 0);
-+ }
-+ }
-+ }
-+ if (gotgint.b.hstnegsucstschng) {
-+ /* Print statements during the HNP interrupt handling
-+ * can cause it to fail.*/
-+ gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
-+ /* WA for 3.00a- HW is not setting cur_mode, even sometimes
-+ * this does not help*/
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a)
-+ dwc_udelay(100);
-+ if (gotgctl.b.hstnegscs) {
-+ if (dwc_otg_is_host_mode(core_if)) {
-+ core_if->op_state = B_HOST;
-+ /*
-+ * Need to disable SOF interrupt immediately.
-+ * When switching from device to host, the PCD
-+ * interrupt handler won't handle the
-+ * interrupt if host mode is already set. The
-+ * HCD interrupt handler won't get called if
-+ * the HCD state is HALT. This means that the
-+ * interrupt does not get handled and Linux
-+ * complains loudly.
-+ */
-+ gintmsk.d32 = 0;
-+ gintmsk.b.sofintr = 1;
-+ DWC_MODIFY_REG32(&global_regs->gintmsk,
-+ gintmsk.d32, 0);
-+ /* Call callback function with spin lock released */
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_pcd_stop(core_if);
-+ /*
-+ * Initialize the Core for Host mode.
-+ */
-+ cil_hcd_start(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ core_if->op_state = B_HOST;
-+ }
-+ } else {
-+ gotgctl.d32 = 0;
-+ gotgctl.b.hnpreq = 1;
-+ gotgctl.b.devhnpen = 1;
-+ DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
-+ DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
-+ __DWC_ERROR("Device Not Connected/Responding\n");
-+ }
-+ }
-+ if (gotgint.b.hstnegdet) {
-+ /* The disconnect interrupt is set at the same time as
-+ * Host Negotiation Detected. During the mode
-+ * switch all interrupts are cleared so the disconnect
-+ * interrupt handler will not get executed.
-+ */
-+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
-+ "Host Negotiation Detected++ (%s)\n",
-+ (dwc_otg_is_host_mode(core_if) ? "Host" :
-+ "Device"));
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
-+ core_if->op_state);
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_hcd_disconnect(core_if);
-+ cil_pcd_start(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ core_if->op_state = A_PERIPHERAL;
-+ } else {
-+ /*
-+ * Need to disable SOF interrupt immediately. When
-+ * switching from device to host, the PCD interrupt
-+ * handler won't handle the interrupt if host mode is
-+ * already set. The HCD interrupt handler won't get
-+ * called if the HCD state is HALT. This means that
-+ * the interrupt does not get handled and Linux
-+ * complains loudly.
-+ */
-+ gintmsk.d32 = 0;
-+ gintmsk.b.sofintr = 1;
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_pcd_stop(core_if);
-+ cil_hcd_start(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ core_if->op_state = A_HOST;
-+ }
-+ }
-+ if (gotgint.b.adevtoutchng) {
-+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
-+ "A-Device Timeout Change++\n");
-+ }
-+ if (gotgint.b.debdone) {
-+ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
-+ }
-+
-+ /* Clear GOTGINT */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
-+
-+ return 1;
-+}
-+
-+void w_conn_id_status_change(void *p)
-+{
-+ dwc_otg_core_if_t *core_if = p;
-+ uint32_t count = 0;
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+
-+ gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
-+ DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
-+
-+ /* B-Device connector (Device Mode) */
-+ if (gotgctl.b.conidsts) {
-+ /* Wait for switch to device mode. */
-+ while (!dwc_otg_is_device_mode(core_if)) {
-+ DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
-+ (dwc_otg_is_host_mode(core_if) ? "Host" :
-+ "Peripheral"));
-+ dwc_mdelay(100);
-+ if (++count > 10000)
-+ break;
-+ }
-+ DWC_ASSERT(++count < 10000,
-+ "Connection id status change timed out");
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ } else {
-+ /* A-Device connector (Host Mode) */
-+ while (!dwc_otg_is_host_mode(core_if)) {
-+ DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
-+ (dwc_otg_is_host_mode(core_if) ? "Host" :
-+ "Peripheral"));
-+ dwc_mdelay(100);
-+ if (++count > 10000)
-+ break;
-+ }
-+ DWC_ASSERT(++count < 10000,
-+ "Connection id status change timed out");
-+ core_if->op_state = A_HOST;
-+ /*
-+ * Initialize the Core for Host mode.
-+ */
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+ }
-+}
-+
-+/**
-+ * This function handles the Connector ID Status Change Interrupt. It
-+ * reads the OTG Interrupt Register (GOTCTL) to determine whether this
-+ * is a Device to Host Mode transition or a Host Mode to Device
-+ * Transition.
-+ *
-+ * This only occurs when the cable is connected/removed from the PHY
-+ * connector.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
-+{
-+
-+ /*
-+ * Need to disable SOF interrupt immediately. If switching from device
-+ * to host, the PCD interrupt handler won't handle the interrupt if
-+ * host mode is already set. The HCD interrupt handler won't get
-+ * called if the HCD state is HALT. This means that the interrupt does
-+ * not get handled and Linux complains loudly.
-+ */
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+ gintsts_data_t gintsts = {.d32 = 0 };
-+
-+ gintmsk.b.sofintr = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
-+
-+ DWC_DEBUGPL(DBG_CIL,
-+ " ++Connector ID Status Change Interrupt++ (%s)\n",
-+ (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
-+
-+ DWC_SPINUNLOCK(core_if->lock);
-+
-+ /*
-+ * Need to schedule a work, as there are possible DELAY function calls
-+ * Release lock before scheduling workq as it holds spinlock during scheduling
-+ */
-+
-+ DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
-+ core_if, "connection id status change");
-+ DWC_SPINLOCK(core_if->lock);
-+
-+ /* Set flag and clear interrupt */
-+ gintsts.b.conidstschng = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that a device is initiating the Session
-+ * Request Protocol to request the host to turn on bus power so a new
-+ * session can begin. The handler responds by turning on bus power. If
-+ * the DWC_otg controller is in low power mode, the handler brings the
-+ * controller out of low power mode before turning on bus power.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gintsts_data_t gintsts;
-+
-+#ifndef DWC_HOST_ONLY
-+ DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
-+
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ DWC_PRINTF("SRP: Device mode\n");
-+ } else {
-+ hprt0_data_t hprt0;
-+ DWC_PRINTF("SRP: Host mode\n");
-+
-+ /* Turn on the port power bit. */
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtpwr = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ /* Start the Connection timer. So a message can be displayed
-+ * if connect does not occur within 10 seconds. */
-+ cil_hcd_session_start(core_if);
-+ }
-+#endif
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.sessreqintr = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+void w_wakeup_detected(void *p)
-+{
-+ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
-+ /*
-+ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
-+ * so that OPT tests pass with all PHYs).
-+ */
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+#if 0
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ /* Restart the Phy Clock */
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+ dwc_udelay(10);
-+#endif //0
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
-+// dwc_mdelay(70);
-+ hprt0.b.prtres = 0; /* Resume */
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
-+ DWC_READ_REG32(core_if->host_if->hprt0));
-+
-+ cil_hcd_resume(core_if);
-+
-+ /** Change to L0 state*/
-+ core_if->lx_state = DWC_OTG_L0;
-+}
-+
-+/**
-+ * This interrupt indicates that the DWC_otg controller has detected a
-+ * resume or remote wakeup sequence. If the DWC_otg controller is in
-+ * low power mode, the handler must brings the controller out of low
-+ * power mode. The controller automatically begins resume
-+ * signaling. The handler schedules a time to stop resume signaling.
-+ */
-+int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gintsts_data_t gintsts;
-+
-+ DWC_DEBUGPL(DBG_ANY,
-+ "++Resume and Remote Wakeup Detected Interrupt++\n");
-+
-+ DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
-+
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ dctl_data_t dctl = {.d32 = 0 };
-+ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
-+ dsts));
-+ if (core_if->lx_state == DWC_OTG_L2) {
-+#ifdef PARTIAL_POWER_DOWN
-+ if (core_if->hwcfg4.b.power_optimiz) {
-+ pcgcctl_data_t power = {.d32 = 0 };
-+
-+ power.d32 = DWC_READ_REG32(core_if->pcgcctl);
-+ DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
-+ power.d32);
-+
-+ power.b.stoppclk = 0;
-+ DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
-+
-+ power.b.pwrclmp = 0;
-+ DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
-+
-+ power.b.rstpdwnmodule = 0;
-+ DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
-+ }
-+#endif
-+ /* Clear the Remote Wakeup Signaling */
-+ dctl.b.rmtwkupsig = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ dctl, dctl.d32, 0);
-+
-+ DWC_SPINUNLOCK(core_if->lock);
-+ if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
-+ core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
-+ }
-+ DWC_SPINLOCK(core_if->lock);
-+ } else {
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ lpmcfg.b.hird_thres &= (~(1 << 4));
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
-+ lpmcfg.d32);
-+ }
-+ /** Change to L0 state*/
-+ core_if->lx_state = DWC_OTG_L0;
-+ } else {
-+ if (core_if->lx_state != DWC_OTG_L1) {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+
-+ /* Restart the Phy Clock */
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+ DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
-+ } else {
-+ /** Change to L0 state*/
-+ core_if->lx_state = DWC_OTG_L0;
-+ }
-+ }
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.wkupintr = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that the Wakeup Logic has detected a
-+ * Device disconnect.
-+ */
-+static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
-+{
-+ gpwrdn_data_t gpwrdn = { .d32 = 0 };
-+ gpwrdn_data_t gpwrdn_temp = { .d32 = 0 };
-+ gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+
-+ DWC_PRINTF("%s called\n", __FUNCTION__);
-+
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ }
-+
-+ /* Switch on the voltage to the core */
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset the core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps*/
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Remove reset the core signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ core_if->hibernation_suspend = 0;
-+
-+ /* Disable PMU */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ if (gpwrdn_temp.b.idsts) {
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ } else {
-+ core_if->op_state = A_HOST;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that the Wakeup Logic has detected a
-+ * remote wakeup sequence.
-+ */
-+static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ DWC_DEBUGPL(DBG_ANY,
-+ "++Powerdown Remote Wakeup Detected Interrupt++\n");
-+
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ }
-+
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ if (gpwrdn.b.idsts) { // Device Mode
-+ if ((core_if->power_down == 2)
-+ && (core_if->hibernation_suspend == 1)) {
-+ dwc_otg_device_hibernation_restore(core_if, 0, 0);
-+ }
-+ } else {
-+ if ((core_if->power_down == 2)
-+ && (core_if->hibernation_suspend == 1)) {
-+ dwc_otg_host_hibernation_restore(core_if, 1, 0);
-+ }
-+ }
-+ return 1;
-+}
-+
-+static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
-+ dwc_otg_core_if_t *core_if = otg_dev->core_if;
-+
-+ DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
-+ gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ if (core_if->power_down == 2) {
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ }
-+ DWC_DEBUGPL(DBG_ANY, "Exit from hibernation on ID sts change\n");
-+ /* Switch on the voltage to the core */
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset the core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Remove reset the core signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /*Indicates that we are exiting from hibernation */
-+ core_if->hibernation_suspend = 0;
-+
-+ /* Disable PMU */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
-+ if (gpwrdn.b.dis_vbus == 1) {
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.dis_vbus = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ }
-+
-+ if (gpwrdn_temp.b.idsts) {
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ } else {
-+ core_if->op_state = A_HOST;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+ }
-+ }
-+
-+ if (core_if->adp_enable) {
-+ uint8_t is_host = 0;
-+ DWC_SPINUNLOCK(core_if->lock);
-+ /* Change the core_if's lock to hcd/pcd lock depend on mode? */
-+#ifndef DWC_HOST_ONLY
-+ if (gpwrdn_temp.b.idsts)
-+ core_if->lock = otg_dev->pcd->lock;
-+#endif
-+#ifndef DWC_DEVICE_ONLY
-+ if (!gpwrdn_temp.b.idsts) {
-+ core_if->lock = otg_dev->hcd->lock;
-+ is_host = 1;
-+ }
-+#endif
-+ DWC_PRINTF("RESTART ADP\n");
-+ if (core_if->adp.probe_enabled)
-+ dwc_otg_adp_probe_stop(core_if);
-+ if (core_if->adp.sense_enabled)
-+ dwc_otg_adp_sense_stop(core_if);
-+ if (core_if->adp.sense_timer_started)
-+ DWC_TIMER_CANCEL(core_if->adp.sense_timer);
-+ if (core_if->adp.vbuson_timer_started)
-+ DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
-+ core_if->adp.probe_timer_values[0] = -1;
-+ core_if->adp.probe_timer_values[1] = -1;
-+ core_if->adp.sense_timer_started = 0;
-+ core_if->adp.vbuson_timer_started = 0;
-+ core_if->adp.probe_counter = 0;
-+ core_if->adp.gpwrdn = 0;
-+
-+ /* Disable PMU and restart ADP */
-+ gpwrdn_temp.d32 = 0;
-+ gpwrdn_temp.b.pmuactv = 1;
-+ gpwrdn_temp.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ DWC_PRINTF("Check point 1\n");
-+ dwc_mdelay(110);
-+ dwc_otg_adp_start(core_if, is_host);
-+ DWC_SPINLOCK(core_if->lock);
-+ }
-+
-+
-+ return 1;
-+}
-+
-+static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t * core_if)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ int32_t otg_cap_param = core_if->core_params->otg_cap;
-+ DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
-+
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ if (core_if->power_down == 2) {
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ }
-+
-+ if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
-+ otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
-+ gpwrdn.b.bsessvld == 0) {
-+ /* Save gpwrdn register for further usage if stschng interrupt */
-+ core_if->gr_backup->gpwrdn_local =
-+ DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
-+ return 1;
-+ }
-+
-+ /* Switch on the voltage to the core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset the core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Remove reset the core signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /*Indicates that we are exiting from hibernation */
-+ core_if->hibernation_suspend = 0;
-+
-+ /* Disable PMU */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+
-+ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
-+ otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
-+ /*
-+ * Initiate SRP after initial ADP probe.
-+ */
-+ dwc_otg_initiate_srp(core_if);
-+ }
-+ }
-+
-+ return 1;
-+}
-+/**
-+ * This interrupt indicates that the Wakeup Logic has detected a
-+ * status change either on IDDIG or BSessVld.
-+ */
-+static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
-+{
-+ int retval;
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
-+ dwc_otg_core_if_t *core_if = otg_dev->core_if;
-+
-+ DWC_PRINTF("%s called\n", __FUNCTION__);
-+
-+ if (core_if->power_down == 2) {
-+ if (core_if->hibernation_suspend <= 0) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ } else
-+ gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
-+
-+ } else {
-+ gpwrdn_temp.d32 = core_if->adp.gpwrdn;
-+ }
-+
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+
-+ if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
-+ retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
-+ } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
-+ retval = dwc_otg_handle_pwrdn_session_change(core_if);
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This interrupt indicates that the Wakeup Logic has detected a
-+ * SRP.
-+ */
-+static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+
-+ DWC_PRINTF("%s called\n", __FUNCTION__);
-+
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return 1;
-+ }
-+#ifdef DWC_DEV_SRPCAP
-+ if (core_if->pwron_timer_started) {
-+ core_if->pwron_timer_started = 0;
-+ DWC_TIMER_CANCEL(core_if->pwron_timer);
-+ }
-+#endif
-+
-+ /* Switch on the voltage to the core */
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset the core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Remove reset the core signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Indicates that we are exiting from hibernation */
-+ core_if->hibernation_suspend = 0;
-+
-+ /* Disable PMU */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Programm Disable VBUS to 0 */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.dis_vbus = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /*Initialize the core as Host */
-+ core_if->op_state = A_HOST;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+
-+ return 1;
-+}
-+
-+/** This interrupt indicates that restore command after Hibernation
-+ * was completed by the core. */
-+int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t * core_if)
-+{
-+ pcgcctl_data_t pcgcctl;
-+ DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
-+
-+ //TODO De-assert restore signal. 8.a
-+ pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
-+ if (pcgcctl.b.restoremode == 1) {
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+ /*
-+ * If restore mode is Remote Wakeup,
-+ * unmask Remote Wakeup interrupt.
-+ */
-+ gintmsk.b.wkupintr = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
-+ 0, gintmsk.d32);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that a device has been disconnected from
-+ * the root port.
-+ */
-+int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gintsts_data_t gintsts;
-+
-+ DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
-+ (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
-+ op_state_str(core_if));
-+
-+/** @todo Consolidate this if statement. */
-+#ifndef DWC_HOST_ONLY
-+ if (core_if->op_state == B_HOST) {
-+ /* If in device mode Disconnect and stop the HCD, then
-+ * start the PCD. */
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_hcd_disconnect(core_if);
-+ cil_pcd_start(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ core_if->op_state = B_PERIPHERAL;
-+ } else if (dwc_otg_is_device_mode(core_if)) {
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+ gotgctl.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
-+ if (gotgctl.b.hstsethnpen == 1) {
-+ /* Do nothing, if HNP in process the OTG
-+ * interrupt "Host Negotiation Detected"
-+ * interrupt will do the mode switch.
-+ */
-+ } else if (gotgctl.b.devhnpen == 0) {
-+ /* If in device mode Disconnect and stop the HCD, then
-+ * start the PCD. */
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_hcd_disconnect(core_if);
-+ cil_pcd_start(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ core_if->op_state = B_PERIPHERAL;
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
-+ }
-+ } else {
-+ if (core_if->op_state == A_HOST) {
-+ /* A-Cable still connected but device disconnected. */
-+ cil_hcd_disconnect(core_if);
-+ if (core_if->adp_enable) {
-+ gpwrdn_data_t gpwrdn = { .d32 = 0 };
-+ cil_hcd_stop(core_if);
-+ /* Enable Power Down Logic */
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_otg_adp_probe_start(core_if);
-+
-+ /* Power off the core */
-+ if (core_if->power_down == 2) {
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32
-+ (&core_if->core_global_regs->gpwrdn,
-+ gpwrdn.d32, 0);
-+ }
-+ }
-+ }
-+ }
-+#endif
-+ /* Change to L3(OFF) state */
-+ core_if->lx_state = DWC_OTG_L3;
-+
-+ gintsts.d32 = 0;
-+ gintsts.b.disconnect = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that SUSPEND state has been detected on
-+ * the USB.
-+ *
-+ * For HNP the USB Suspend interrupt signals the change from
-+ * "a_peripheral" to "a_host".
-+ *
-+ * When power management is enabled the core will be put in low power
-+ * mode.
-+ */
-+int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
-+{
-+ dsts_data_t dsts;
-+ gintsts_data_t gintsts;
-+ dcfg_data_t dcfg;
-+
-+ DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
-+
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ /* Check the Device status register to determine if the Suspend
-+ * state is active. */
-+ dsts.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
-+ DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
-+ "HWCFG4.power Optimize=%d\n",
-+ dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
-+
-+#ifdef PARTIAL_POWER_DOWN
-+/** @todo Add a module parameter for power management. */
-+
-+ if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
-+ pcgcctl_data_t power = {.d32 = 0 };
-+ DWC_DEBUGPL(DBG_CIL, "suspend\n");
-+
-+ power.b.pwrclmp = 1;
-+ DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
-+
-+ power.b.rstpdwnmodule = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
-+
-+ power.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
-+
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
-+ }
-+#endif
-+ /* PCD callback for suspend. Release the lock inside of callback function */
-+ cil_pcd_suspend(core_if);
-+ if (core_if->power_down == 2)
-+ {
-+ dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ DWC_DEBUGPL(DBG_ANY,"lx_state = %08x\n",core_if->lx_state);
-+ DWC_DEBUGPL(DBG_ANY," device address = %08d\n",dcfg.b.devaddr);
-+
-+ if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ gusbcfg_data_t gusbcfg = {.d32 = 0 };
-+
-+ /* Change to L2(suspend) state */
-+ core_if->lx_state = DWC_OTG_L2;
-+
-+ /* Clear interrupt in gintsts */
-+ gintsts.d32 = 0;
-+ gintsts.b.usbsuspend = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->
-+ gintsts, gintsts.d32);
-+ DWC_PRINTF("Start of hibernation completed\n");
-+ dwc_otg_save_global_regs(core_if);
-+ dwc_otg_save_dev_regs(core_if);
-+
-+ gusbcfg.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->
-+ gusbcfg);
-+ if (gusbcfg.b.ulpi_utmi_sel == 1) {
-+ /* ULPI interface */
-+ /* Suspend the Phy Clock */
-+ pcgcctl.d32 = 0;
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0,
-+ pcgcctl.d32);
-+ dwc_udelay(10);
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ } else {
-+ /* UTMI+ Interface */
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0,
-+ pcgcctl.d32);
-+ dwc_udelay(10);
-+ }
-+
-+ /* Set flag to indicate that we are in hibernation */
-+ core_if->hibernation_suspend = 1;
-+ /* Enable interrupts from wake up logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Unmask device mode interrupts in GPWRDN */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.rst_det_msk = 1;
-+ gpwrdn.b.lnstchng_msk = 1;
-+ gpwrdn.b.sts_chngint_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Enable Power Down Clamp */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Switch off VDD */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+
-+ /* Save gpwrdn register for further usage if stschng interrupt */
-+ core_if->gr_backup->gpwrdn_local =
-+ DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ DWC_PRINTF("Hibernation completed\n");
-+
-+ return 1;
-+ }
-+ } else if (core_if->power_down == 3) {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
-+ DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",core_if->lx_state);
-+ DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",dcfg.b.devaddr);
-+
-+ if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
-+ DWC_DEBUGPL(DBG_ANY, "Start entering to extended hibernation\n");
-+ core_if->xhib = 1;
-+
-+ /* Clear interrupt in gintsts */
-+ gintsts.d32 = 0;
-+ gintsts.b.usbsuspend = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->
-+ gintsts, gintsts.d32);
-+
-+ dwc_otg_save_global_regs(core_if);
-+ dwc_otg_save_dev_regs(core_if);
-+
-+ /* Wait for 10 PHY clocks */
-+ dwc_udelay(10);
-+
-+ /* Program GPIO register while entering to xHib */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x1);
-+
-+ pcgcctl.b.enbl_extnd_hiber = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
-+
-+ pcgcctl.d32 = 0;
-+ pcgcctl.b.extnd_hiber_pwrclmp = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
-+
-+ pcgcctl.d32 = 0;
-+ pcgcctl.b.extnd_hiber_switch = 1;
-+ core_if->gr_backup->xhib_gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ core_if->gr_backup->xhib_pcgcctl = DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.d32;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
-+
-+ DWC_DEBUGPL(DBG_ANY, "Finished entering to extended hibernation\n");
-+
-+ return 1;
-+ }
-+ }
-+ } else {
-+ if (core_if->op_state == A_PERIPHERAL) {
-+ DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
-+ /* Clear the a_peripheral flag, back to a_host. */
-+ DWC_SPINUNLOCK(core_if->lock);
-+ cil_pcd_stop(core_if);
-+ cil_hcd_start(core_if);
-+ DWC_SPINLOCK(core_if->lock);
-+ core_if->op_state = A_HOST;
-+ }
-+ }
-+
-+ /* Change to L2(suspend) state */
-+ core_if->lx_state = DWC_OTG_L2;
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.usbsuspend = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t * core_if)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ gahbcfg_data_t gahbcfg = {.d32 = 0 };
-+
-+ dwc_udelay(10);
-+
-+ /* Program GPIO register while entering to xHib */
-+ DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
-+
-+ pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
-+ pcgcctl.b.extnd_hiber_pwrclmp = 0;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+ dwc_udelay(10);
-+
-+ gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
-+ gpwrdn.b.restore = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ restore_lpm_i2c_regs(core_if);
-+
-+ pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
-+ pcgcctl.b.max_xcvrselect = 1;
-+ pcgcctl.b.ess_reg_restored = 0;
-+ pcgcctl.b.extnd_hiber_switch = 0;
-+ pcgcctl.b.extnd_hiber_pwrclmp = 0;
-+ pcgcctl.b.enbl_extnd_hiber = 1;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+
-+ gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
-+ gahbcfg.b.glblintrmsk = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
-+ core_if->gr_backup->gusbcfg_local);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
-+ core_if->dr_backup->dcfg);
-+
-+ pcgcctl.d32 = 0;
-+ pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
-+ pcgcctl.b.max_xcvrselect = 1;
-+ pcgcctl.d32 |= 0x608;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+ dwc_udelay(10);
-+
-+ pcgcctl.d32 = 0;
-+ pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
-+ pcgcctl.b.max_xcvrselect = 1;
-+ pcgcctl.b.ess_reg_restored = 1;
-+ pcgcctl.b.enbl_extnd_hiber = 1;
-+ pcgcctl.b.rstpdwnmodule = 1;
-+ pcgcctl.b.restoremode = 1;
-+ DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
-+
-+ DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
-+
-+ return 1;
-+}
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+/**
-+ * This function hadles LPM transaction received interrupt.
-+ */
-+static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ gintsts_data_t gintsts;
-+
-+ if (!core_if->core_params->lpm_enable) {
-+ DWC_PRINTF("Unexpected LPM interrupt\n");
-+ }
-+
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
-+
-+ if (dwc_otg_is_host_mode(core_if)) {
-+ cil_hcd_sleep(core_if);
-+ } else {
-+ lpmcfg.b.hird_thres |= (1 << 4);
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
-+ lpmcfg.d32);
-+ }
-+
-+ /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
-+ dwc_udelay(10);
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ if (lpmcfg.b.prt_sleep_sts) {
-+ /* Save the current state */
-+ core_if->lx_state = DWC_OTG_L1;
-+ }
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.lpmtranrcvd = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+ return 1;
-+}
-+#endif /* CONFIG_USB_DWC_OTG_LPM */
-+
-+/**
-+ * This function returns the Core Interrupt register.
-+ */
-+static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk)
-+{
-+ gahbcfg_data_t gahbcfg = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+ gintmsk_data_t gintmsk;
-+ gintmsk_data_t gintmsk_common = {.d32 = 0 };
-+ gintmsk_common.b.wkupintr = 1;
-+ gintmsk_common.b.sessreqintr = 1;
-+ gintmsk_common.b.conidstschng = 1;
-+ gintmsk_common.b.otgintr = 1;
-+ gintmsk_common.b.modemismatch = 1;
-+ gintmsk_common.b.disconnect = 1;
-+ gintmsk_common.b.usbsuspend = 1;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ gintmsk_common.b.lpmtranrcvd = 1;
-+#endif
-+ gintmsk_common.b.restoredone = 1;
-+ if(dwc_otg_is_device_mode(core_if))
-+ {
-+ /** @todo: The port interrupt occurs while in device
-+ * mode. Added code to CIL to clear the interrupt for now!
-+ */
-+ gintmsk_common.b.portintr = 1;
-+ }
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+ {
-+ unsigned long flags;
-+
-+ // Re-enable the saved interrupts
-+ local_irq_save(flags);
-+ local_fiq_disable();
-+ gintmsk.d32 |= gintmsk_common.d32;
-+ gintsts_saved.d32 &= ~gintmsk_common.d32;
-+ reenable_gintmsk->d32 = gintmsk.d32;
-+ local_irq_restore(flags);
-+ }
-+
-+ gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
-+
-+#ifdef DEBUG
-+ /* if any common interrupts set */
-+ if (gintsts.d32 & gintmsk_common.d32) {
-+ DWC_DEBUGPL(DBG_ANY, "common_intr: gintsts=%08x gintmsk=%08x\n",
-+ gintsts.d32, gintmsk.d32);
-+ }
-+#endif
-+ if (!fiq_fix_enable){
-+ if (gahbcfg.b.glblintrmsk)
-+ return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
-+ else
-+ return 0;
-+ }
-+ else {
-+ return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
-+ }
-+
-+}
-+
-+/* MACRO for clearing interupt bits in GPWRDN register */
-+#define CLEAR_GPWRDN_INTR(__core_if,__intr) \
-+do { \
-+ gpwrdn_data_t gpwrdn = {.d32=0}; \
-+ gpwrdn.b.__intr = 1; \
-+ DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
-+ 0, gpwrdn.d32); \
-+} while (0)
-+
-+/**
-+ * Common interrupt handler.
-+ *
-+ * The common interrupts are those that occur in both Host and Device mode.
-+ * This handler handles the following interrupts:
-+ * - Mode Mismatch Interrupt
-+ * - Disconnect Interrupt
-+ * - OTG Interrupt
-+ * - Connector ID Status Change Interrupt
-+ * - Session Request Interrupt.
-+ * - Resume / Remote Wakeup Detected Interrupt.
-+ * - LPM Transaction Received Interrupt
-+ * - ADP Transaction Received Interrupt
-+ *
-+ */
-+int32_t dwc_otg_handle_common_intr(void *dev)
-+{
-+ int retval = 0;
-+ gintsts_data_t gintsts;
-+ gintmsk_data_t reenable_gintmsk;
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ dwc_otg_device_t *otg_dev = dev;
-+ dwc_otg_core_if_t *core_if = otg_dev->core_if;
-+ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+ if (dwc_otg_is_device_mode(core_if))
-+ core_if->frame_num = dwc_otg_get_frame_number(core_if);
-+
-+ if (core_if->lock)
-+ DWC_SPINLOCK(core_if->lock);
-+
-+ if (core_if->power_down == 3 && core_if->xhib == 1) {
-+ DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
-+ retval |= dwc_otg_handle_xhib_exit_intr(core_if);
-+ core_if->xhib = 2;
-+ if (core_if->lock)
-+ DWC_SPINUNLOCK(core_if->lock);
-+
-+ return retval;
-+ }
-+
-+ if (core_if->hibernation_suspend <= 0) {
-+ gintsts.d32 = dwc_otg_read_common_intr(core_if, &reenable_gintmsk);
-+
-+ if (gintsts.b.modemismatch) {
-+ retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
-+ }
-+ if (gintsts.b.otgintr) {
-+ retval |= dwc_otg_handle_otg_intr(core_if);
-+ }
-+ if (gintsts.b.conidstschng) {
-+ retval |=
-+ dwc_otg_handle_conn_id_status_change_intr(core_if);
-+ }
-+ if (gintsts.b.disconnect) {
-+ retval |= dwc_otg_handle_disconnect_intr(core_if);
-+ }
-+ if (gintsts.b.sessreqintr) {
-+ retval |= dwc_otg_handle_session_req_intr(core_if);
-+ }
-+ if (gintsts.b.wkupintr) {
-+ retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
-+ }
-+ if (gintsts.b.usbsuspend) {
-+ retval |= dwc_otg_handle_usb_suspend_intr(core_if);
-+ }
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ if (gintsts.b.lpmtranrcvd) {
-+ retval |= dwc_otg_handle_lpm_intr(core_if);
-+ }
-+#endif
-+ if (gintsts.b.restoredone) {
-+ gintsts.d32 = 0;
-+ if (core_if->power_down == 2)
-+ core_if->hibernation_suspend = -1;
-+ else if (core_if->power_down == 3 && core_if->xhib == 2) {
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ dctl_data_t dctl = {.d32 = 0 };
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->
-+ gintsts, 0xFFFFFFFF);
-+
-+ DWC_DEBUGPL(DBG_ANY,
-+ "RESTORE DONE generated\n");
-+
-+ gpwrdn.b.restore = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ pcgcctl.b.rstpdwnmodule = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, core_if->gr_backup->gusbcfg_local);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, core_if->dr_backup->dcfg);
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, core_if->dr_backup->dctl);
-+ dwc_udelay(50);
-+
-+ dctl.b.pwronprgdone = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ dwc_udelay(10);
-+
-+ dwc_otg_restore_global_regs(core_if);
-+ dwc_otg_restore_dev_regs(core_if, 0);
-+
-+ dctl.d32 = 0;
-+ dctl.b.pwronprgdone = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
-+ dwc_udelay(10);
-+
-+ pcgcctl.d32 = 0;
-+ pcgcctl.b.enbl_extnd_hiber = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+
-+ /* The core will be in ON STATE */
-+ core_if->lx_state = DWC_OTG_L0;
-+ core_if->xhib = 0;
-+
-+ DWC_SPINUNLOCK(core_if->lock);
-+ if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
-+ core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
-+ }
-+ DWC_SPINLOCK(core_if->lock);
-+
-+ }
-+
-+ gintsts.b.restoredone = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
-+ DWC_PRINTF(" --Restore done interrupt received-- \n");
-+ retval |= 1;
-+ }
-+ if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
-+ /* The port interrupt occurs while in device mode with HPRT0
-+ * Port Enable/Disable.
-+ */
-+ gintsts.d32 = 0;
-+ gintsts.b.portintr = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
-+ retval |= 1;
-+ reenable_gintmsk.b.portintr = 1;
-+
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, reenable_gintmsk.d32);
-+
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
-+
-+ if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
-+ CLEAR_GPWRDN_INTR(core_if, disconn_det);
-+ if (gpwrdn.b.linestate == 0) {
-+ dwc_otg_handle_pwrdn_disconnect_intr(core_if);
-+ } else {
-+ DWC_PRINTF("Disconnect detected while linestate is not 0\n");
-+ }
-+
-+ retval |= 1;
-+ }
-+ if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
-+ CLEAR_GPWRDN_INTR(core_if, lnstschng);
-+ /* remote wakeup from hibernation */
-+ if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
-+ dwc_otg_handle_pwrdn_wakeup_detected_intr(core_if);
-+ } else {
-+ DWC_PRINTF("gpwrdn.linestate = %d\n", gpwrdn.b.linestate);
-+ }
-+ retval |= 1;
-+ }
-+ if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
-+ CLEAR_GPWRDN_INTR(core_if, rst_det);
-+ if (gpwrdn.b.linestate == 0) {
-+ DWC_PRINTF("Reset detected\n");
-+ retval |= dwc_otg_device_hibernation_restore(core_if, 0, 1);
-+ }
-+ }
-+ if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
-+ CLEAR_GPWRDN_INTR(core_if, srp_det);
-+ dwc_otg_handle_pwrdn_srp_intr(core_if);
-+ retval |= 1;
-+ }
-+ }
-+ /* Handle ADP interrupt here */
-+ if (gpwrdn.b.adp_int) {
-+ DWC_PRINTF("ADP interrupt\n");
-+ CLEAR_GPWRDN_INTR(core_if, adp_int);
-+ dwc_otg_adp_handle_intr(core_if);
-+ retval |= 1;
-+ }
-+ if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
-+ DWC_PRINTF("STS CHNG interrupt asserted\n");
-+ CLEAR_GPWRDN_INTR(core_if, sts_chngint);
-+ dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
-+
-+ retval |= 1;
-+ }
-+ if (core_if->lock)
-+ DWC_SPINUNLOCK(core_if->lock);
-+
-+ return retval;
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_core_if.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_core_if.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_core_if.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_core_if.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,705 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
-+ * $Revision: #13 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#if !defined(__DWC_CORE_IF_H__)
-+#define __DWC_CORE_IF_H__
-+
-+#include "dwc_os.h"
-+
-+/** @file
-+ * This file defines DWC_OTG Core API
-+ */
-+
-+struct dwc_otg_core_if;
-+typedef struct dwc_otg_core_if dwc_otg_core_if_t;
-+
-+/** Maximum number of Periodic FIFOs */
-+#define MAX_PERIO_FIFOS 15
-+/** Maximum number of Periodic FIFOs */
-+#define MAX_TX_FIFOS 15
-+
-+/** Maximum number of Endpoints/HostChannels */
-+#define MAX_EPS_CHANNELS 16
-+
-+extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
-+extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
-+
-+extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
-+
-+extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
-+extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
-+
-+extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
-+
-+/** This function should be called on every hardware interrupt. */
-+extern int32_t dwc_otg_handle_common_intr(void *otg_dev);
-+
-+/** @name OTG Core Parameters */
-+/** @{ */
-+
-+/**
-+ * Specifies the OTG capabilities. The driver will automatically
-+ * detect the value for this parameter if none is specified.
-+ * 0 - HNP and SRP capable (default)
-+ * 1 - SRP Only capable
-+ * 2 - No HNP/SRP capable
-+ */
-+extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
-+#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
-+#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
-+#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
-+#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
-+
-+extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
-+#define dwc_param_opt_default 1
-+
-+/**
-+ * Specifies whether to use slave or DMA mode for accessing the data
-+ * FIFOs. The driver will automatically detect the value for this
-+ * parameter if none is specified.
-+ * 0 - Slave
-+ * 1 - DMA (default, if available)
-+ */
-+extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
-+#define dwc_param_dma_enable_default 1
-+
-+/**
-+ * When DMA mode is enabled specifies whether to use
-+ * address DMA or DMA Descritor mode for accessing the data
-+ * FIFOs in device mode. The driver will automatically detect
-+ * the value for this parameter if none is specified.
-+ * 0 - address DMA
-+ * 1 - DMA Descriptor(default, if available)
-+ */
-+extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
-+//#define dwc_param_dma_desc_enable_default 1
-+#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708
-+
-+/** The DMA Burst size (applicable only for External DMA
-+ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
-+ */
-+extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
-+#define dwc_param_dma_burst_size_default 32
-+
-+/**
-+ * Specifies the maximum speed of operation in host and device mode.
-+ * The actual speed depends on the speed of the attached device and
-+ * the value of phy_type. The actual speed depends on the speed of the
-+ * attached device.
-+ * 0 - High Speed (default)
-+ * 1 - Full Speed
-+ */
-+extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
-+#define dwc_param_speed_default 0
-+#define DWC_SPEED_PARAM_HIGH 0
-+#define DWC_SPEED_PARAM_FULL 1
-+
-+/** Specifies whether low power mode is supported when attached
-+ * to a Full Speed or Low Speed device in host mode.
-+ * 0 - Don't support low power mode (default)
-+ * 1 - Support low power mode
-+ */
-+extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
-+ core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
-+ * core_if);
-+#define dwc_param_host_support_fs_ls_low_power_default 0
-+
-+/** Specifies the PHY clock rate in low power mode when connected to a
-+ * Low Speed device in host mode. This parameter is applicable only if
-+ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
-+ * then defaults to 6 MHZ otherwise 48 MHZ.
-+ *
-+ * 0 - 48 MHz
-+ * 1 - 6 MHz
-+ */
-+extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
-+ core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
-+ core_if);
-+#define dwc_param_host_ls_low_power_phy_clk_default 0
-+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
-+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
-+
-+/**
-+ * 0 - Use cC FIFO size parameters
-+ * 1 - Allow dynamic FIFO sizing (default)
-+ */
-+extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
-+ core_if);
-+#define dwc_param_enable_dynamic_fifo_default 1
-+
-+/** Total number of 4-byte words in the data FIFO memory. This
-+ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
-+ * Tx FIFOs.
-+ * 32 to 32768 (default 8192)
-+ * Note: The total FIFO memory depth in the FPGA configuration is 8192.
-+ */
-+extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
-+//#define dwc_param_data_fifo_size_default 8192
-+#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708
-+
-+/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
-+ * FIFO sizing is enabled.
-+ * 16 to 32768 (default 1064)
-+ */
-+extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
-+#define dwc_param_dev_rx_fifo_size_default 1064
-+
-+/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
-+ * when dynamic FIFO sizing is enabled.
-+ * 16 to 32768 (default 1024)
-+ */
-+extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if);
-+#define dwc_param_dev_nperio_tx_fifo_size_default 1024
-+
-+/** Number of 4-byte words in each of the periodic Tx FIFOs in device
-+ * mode when dynamic FIFO sizing is enabled.
-+ * 4 to 768 (default 256)
-+ */
-+extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val, int fifo_num);
-+extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if, int fifo_num);
-+#define dwc_param_dev_perio_tx_fifo_size_default 256
-+
-+/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
-+ * FIFO sizing is enabled.
-+ * 16 to 32768 (default 1024)
-+ */
-+extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
-+//#define dwc_param_host_rx_fifo_size_default 1024
-+#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708
-+
-+/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
-+ * when Dynamic FIFO sizing is enabled in the core.
-+ * 16 to 32768 (default 1024)
-+ */
-+extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if);
-+//#define dwc_param_host_nperio_tx_fifo_size_default 1024
-+#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708
-+
-+/** Number of 4-byte words in the host periodic Tx FIFO when dynamic
-+ * FIFO sizing is enabled.
-+ * 16 to 32768 (default 1024)
-+ */
-+extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
-+ core_if);
-+//#define dwc_param_host_perio_tx_fifo_size_default 1024
-+#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708
-+
-+/** The maximum transfer size supported in bytes.
-+ * 2047 to 65,535 (default 65,535)
-+ */
-+extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
-+#define dwc_param_max_transfer_size_default 65535
-+
-+/** The maximum number of packets in a transfer.
-+ * 15 to 511 (default 511)
-+ */
-+extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
-+#define dwc_param_max_packet_count_default 511
-+
-+/** The number of host channel registers to use.
-+ * 1 to 16 (default 12)
-+ * Note: The FPGA configuration supports a maximum of 12 host channels.
-+ */
-+extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
-+//#define dwc_param_host_channels_default 12
-+#define dwc_param_host_channels_default 8 // Broadcom BCM2708
-+
-+/** The number of endpoints in addition to EP0 available for device
-+ * mode operations.
-+ * 1 to 15 (default 6 IN and OUT)
-+ * Note: The FPGA configuration supports a maximum of 6 IN and OUT
-+ * endpoints in addition to EP0.
-+ */
-+extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
-+#define dwc_param_dev_endpoints_default 6
-+
-+/**
-+ * Specifies the type of PHY interface to use. By default, the driver
-+ * will automatically detect the phy_type.
-+ *
-+ * 0 - Full Speed PHY
-+ * 1 - UTMI+ (default)
-+ * 2 - ULPI
-+ */
-+extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
-+#define DWC_PHY_TYPE_PARAM_FS 0
-+#define DWC_PHY_TYPE_PARAM_UTMI 1
-+#define DWC_PHY_TYPE_PARAM_ULPI 2
-+#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
-+
-+/**
-+ * Specifies the UTMI+ Data Width. This parameter is
-+ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
-+ * PHY_TYPE, this parameter indicates the data width between
-+ * the MAC and the ULPI Wrapper.) Also, this parameter is
-+ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
-+ * to "8 and 16 bits", meaning that the core has been
-+ * configured to work at either data path width.
-+ *
-+ * 8 or 16 bits (default 16)
-+ */
-+extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
-+//#define dwc_param_phy_utmi_width_default 16
-+#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708
-+
-+/**
-+ * Specifies whether the ULPI operates at double or single
-+ * data rate. This parameter is only applicable if PHY_TYPE is
-+ * ULPI.
-+ *
-+ * 0 - single data rate ULPI interface with 8 bit wide data
-+ * bus (default)
-+ * 1 - double data rate ULPI interface with 4 bit wide data
-+ * bus
-+ */
-+extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
-+#define dwc_param_phy_ulpi_ddr_default 0
-+
-+/**
-+ * Specifies whether to use the internal or external supply to
-+ * drive the vbus with a ULPI phy.
-+ */
-+extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
-+#define DWC_PHY_ULPI_INTERNAL_VBUS 0
-+#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
-+#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
-+
-+/**
-+ * Specifies whether to use the I2Cinterface for full speed PHY. This
-+ * parameter is only applicable if PHY_TYPE is FS.
-+ * 0 - No (default)
-+ * 1 - Yes
-+ */
-+extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
-+#define dwc_param_i2c_enable_default 0
-+
-+extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
-+#define dwc_param_ulpi_fs_ls_default 0
-+
-+extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
-+#define dwc_param_ts_dline_default 0
-+
-+/**
-+ * Specifies whether dedicated transmit FIFOs are
-+ * enabled for non periodic IN endpoints in device mode
-+ * 0 - No
-+ * 1 - Yes
-+ */
-+extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
-+ core_if);
-+#define dwc_param_en_multiple_tx_fifo_default 1
-+
-+/** Number of 4-byte words in each of the Tx FIFOs in device
-+ * mode when dynamic FIFO sizing is enabled.
-+ * 4 to 768 (default 256)
-+ */
-+extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int fifo_num, int32_t val);
-+extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
-+ int fifo_num);
-+#define dwc_param_dev_tx_fifo_size_default 768
-+
-+/** Thresholding enable flag-
-+ * bit 0 - enable non-ISO Tx thresholding
-+ * bit 1 - enable ISO Tx thresholding
-+ * bit 2 - enable Rx thresholding
-+ */
-+extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
-+#define dwc_param_thr_ctl_default 0
-+
-+/** Thresholding length for Tx
-+ * FIFOs in 32 bit DWORDs
-+ */
-+extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
-+#define dwc_param_tx_thr_length_default 64
-+
-+/** Thresholding length for Rx
-+ * FIFOs in 32 bit DWORDs
-+ */
-+extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
-+#define dwc_param_rx_thr_length_default 64
-+
-+/**
-+ * Specifies whether LPM (Link Power Management) support is enabled
-+ */
-+extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
-+#define dwc_param_lpm_enable_default 1
-+
-+/**
-+ * Specifies whether PTI enhancement is enabled
-+ */
-+extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
-+#define dwc_param_pti_enable_default 0
-+
-+/**
-+ * Specifies whether MPI enhancement is enabled
-+ */
-+extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
-+#define dwc_param_mpi_enable_default 0
-+
-+/**
-+ * Specifies whether ADP capability is enabled
-+ */
-+extern int dwc_otg_set_param_adp_enable(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_adp_enable(dwc_otg_core_if_t * core_if);
-+#define dwc_param_adp_enable_default 0
-+
-+/**
-+ * Specifies whether IC_USB capability is enabled
-+ */
-+
-+extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
-+#define dwc_param_ic_usb_cap_default 0
-+
-+extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
-+#define dwc_param_ahb_thr_ratio_default 0
-+
-+extern int dwc_otg_set_param_power_down(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_power_down(dwc_otg_core_if_t * core_if);
-+#define dwc_param_power_down_default 0
-+
-+extern int dwc_otg_set_param_reload_ctl(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_reload_ctl(dwc_otg_core_if_t * core_if);
-+#define dwc_param_reload_ctl_default 0
-+
-+extern int dwc_otg_set_param_dev_out_nak(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_dev_out_nak(dwc_otg_core_if_t * core_if);
-+#define dwc_param_dev_out_nak_default 0
-+
-+extern int dwc_otg_set_param_cont_on_bna(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_cont_on_bna(dwc_otg_core_if_t * core_if);
-+#define dwc_param_cont_on_bna_default 0
-+
-+extern int dwc_otg_set_param_ahb_single(dwc_otg_core_if_t * core_if,
-+ int32_t val);
-+extern int32_t dwc_otg_get_param_ahb_single(dwc_otg_core_if_t * core_if);
-+#define dwc_param_ahb_single_default 0
-+
-+extern int dwc_otg_set_param_otg_ver(dwc_otg_core_if_t * core_if, int32_t val);
-+extern int32_t dwc_otg_get_param_otg_ver(dwc_otg_core_if_t * core_if);
-+#define dwc_param_otg_ver_default 0
-+
-+/** @} */
-+
-+/** @name Access to registers and bit-fields */
-+
-+/**
-+ * Dump core registers and SPRAM
-+ */
-+extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
-+extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
-+
-+/**
-+ * Get host negotiation status.
-+ */
-+extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get srp status
-+ */
-+extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Set hnpreq bit in the GOTGCTL register.
-+ */
-+extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get Content of SNPSID register.
-+ */
-+extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get current mode.
-+ * Returns 0 if in device mode, and 1 if in host mode.
-+ */
-+extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get value of hnpcapable field in the GUSBCFG register
-+ */
-+extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of hnpcapable field in the GUSBCFG register
-+ */
-+extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of srpcapable field in the GUSBCFG register
-+ */
-+extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of srpcapable field in the GUSBCFG register
-+ */
-+extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of devspeed field in the DCFG register
-+ */
-+extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of devspeed field in the DCFG register
-+ */
-+extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get the value of busconnected field from the HPRT0 register
-+ */
-+extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Gets the device enumeration Speed.
-+ */
-+extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get value of prtpwr field from the HPRT0 register
-+ */
-+extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get value of flag indicating core state - hibernated or not
-+ */
-+extern uint32_t dwc_otg_get_core_state(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Set value of prtpwr field from the HPRT0 register
-+ */
-+extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of prtsusp field from the HPRT0 regsiter
-+ */
-+extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of prtpwr field from the HPRT0 register
-+ */
-+extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of ModeChTimEn field from the HCFG regsiter
-+ */
-+extern uint32_t dwc_otg_get_mode_ch_tim(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of ModeChTimEn field from the HCFG regsiter
-+ */
-+extern void dwc_otg_set_mode_ch_tim(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of Fram Interval field from the HFIR regsiter
-+ */
-+extern uint32_t dwc_otg_get_fr_interval(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of Frame Interval field from the HFIR regsiter
-+ */
-+extern void dwc_otg_set_fr_interval(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Set value of prtres field from the HPRT0 register
-+ *FIXME Remove?
-+ */
-+extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of rmtwkupsig bit in DCTL register
-+ */
-+extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get value of prt_sleep_sts field from the GLPMCFG register
-+ */
-+extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get value of rem_wkup_en field from the GLPMCFG register
-+ */
-+extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Get value of appl_resp field from the GLPMCFG register
-+ */
-+extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of appl_resp field from the GLPMCFG register
-+ */
-+extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of hsic_connect field from the GLPMCFG register
-+ */
-+extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of hsic_connect field from the GLPMCFG register
-+ */
-+extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * Get value of inv_sel_hsic field from the GLPMCFG register.
-+ */
-+extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
-+/**
-+ * Set value of inv_sel_hsic field from the GLPMFG register.
-+ */
-+extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/*
-+ * Some functions for accessing registers
-+ */
-+
-+/**
-+ * GOTGCTL register
-+ */
-+extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * GUSBCFG register
-+ */
-+extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * GRXFSIZ register
-+ */
-+extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * GNPTXFSIZ register
-+ */
-+extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * GGPIO register
-+ */
-+extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * GUID register
-+ */
-+extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * HPRT0 register
-+ */
-+extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
-+extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
-+
-+/**
-+ * GHPTXFSIZE
-+ */
-+extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
-+
-+/** @} */
-+
-+#endif /* __DWC_CORE_IF_H__ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_dbg.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_dbg.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_dbg.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,117 @@
-+/* ==========================================================================
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#ifndef __DWC_OTG_DBG_H__
-+#define __DWC_OTG_DBG_H__
-+
-+/** @file
-+ * This file defines debug levels.
-+ * Debugging support vanishes in non-debug builds.
-+ */
-+
-+/**
-+ * The Debug Level bit-mask variable.
-+ */
-+extern uint32_t g_dbg_lvl;
-+/**
-+ * Set the Debug Level variable.
-+ */
-+static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
-+{
-+ uint32_t old = g_dbg_lvl;
-+ g_dbg_lvl = new;
-+ return old;
-+}
-+
-+#define DBG_USER (0x1)
-+/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
-+#define DBG_CIL (0x2)
-+/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
-+ * messages */
-+#define DBG_CILV (0x20)
-+/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
-+ * messages */
-+#define DBG_PCD (0x4)
-+/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
-+ * messages */
-+#define DBG_PCDV (0x40)
-+/** When debug level has the DBG_HCD bit set, display Host debug messages */
-+#define DBG_HCD (0x8)
-+/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
-+ * messages */
-+#define DBG_HCDV (0x80)
-+/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
-+ * mode. */
-+#define DBG_HCD_URB (0x800)
-+/** When debug level has the DBG_HCDI bit set, display host interrupt
-+ * messages. */
-+#define DBG_HCDI (0x1000)
-+
-+/** When debug level has any bit set, display debug messages */
-+#define DBG_ANY (0xFF)
-+
-+/** All debug messages off */
-+#define DBG_OFF 0
-+
-+/** Prefix string for DWC_DEBUG print macros. */
-+#define USB_DWC "DWC_otg: "
-+
-+/**
-+ * Print a debug message when the Global debug level variable contains
-+ * the bit defined in <code>lvl</code>.
-+ *
-+ * @param[in] lvl - Debug level, use one of the DBG_ constants above.
-+ * @param[in] x - like printf
-+ *
-+ * Example:<p>
-+ * <code>
-+ * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
-+ * </code>
-+ * <br>
-+ * results in:<br>
-+ * <code>
-+ * usb-DWC_otg: dwc_otg_cil_init(ca867000)
-+ * </code>
-+ */
-+#ifdef DEBUG
-+
-+# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
-+# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
-+
-+# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
-+
-+#else
-+
-+# define DWC_DEBUGPL(lvl, x...) do{}while(0)
-+# define DWC_DEBUGP(x...)
-+
-+# define CHK_DEBUG_LEVEL(level) (0)
-+
-+#endif /*DEBUG*/
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_driver.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_driver.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_driver.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_driver.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1742 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
-+ * $Revision: #92 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+/** @file
-+ * The dwc_otg_driver module provides the initialization and cleanup entry
-+ * points for the DWC_otg driver. This module will be dynamically installed
-+ * after Linux is booted using the insmod command. When the module is
-+ * installed, the dwc_otg_driver_init function is called. When the module is
-+ * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
-+ *
-+ * This module also defines a data structure for the dwc_otg_driver, which is
-+ * used in conjunction with the standard ARM lm_device structure. These
-+ * structures allow the OTG driver to comply with the standard Linux driver
-+ * model in which devices and drivers are registered with a bus driver. This
-+ * has the benefit that Linux can expose attributes of the driver and device
-+ * in its special sysfs file system. Users can then read or write files in
-+ * this file system to perform diagnostics on the driver components or the
-+ * device.
-+ */
-+
-+#include "dwc_otg_os_dep.h"
-+#include "dwc_os.h"
-+#include "dwc_otg_dbg.h"
-+#include "dwc_otg_driver.h"
-+#include "dwc_otg_attr.h"
-+#include "dwc_otg_core_if.h"
-+#include "dwc_otg_pcd_if.h"
-+#include "dwc_otg_hcd_if.h"
-+
-+#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012"
-+#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
-+
-+bool microframe_schedule=true;
-+
-+static const char dwc_driver_name[] = "dwc_otg";
-+
-+extern void* dummy_send;
-+
-+extern int pcd_init(
-+#ifdef LM_INTERFACE
-+ struct lm_device *_dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *_dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *dev
-+#endif
-+ );
-+extern int hcd_init(
-+#ifdef LM_INTERFACE
-+ struct lm_device *_dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *_dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *dev
-+#endif
-+ );
-+
-+extern int pcd_remove(
-+#ifdef LM_INTERFACE
-+ struct lm_device *_dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *_dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *_dev
-+#endif
-+ );
-+
-+extern void hcd_remove(
-+#ifdef LM_INTERFACE
-+ struct lm_device *_dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *_dev
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *_dev
-+#endif
-+ );
-+
-+extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
-+
-+/*-------------------------------------------------------------------------*/
-+/* Encapsulate the module parameter settings */
-+
-+struct dwc_otg_driver_module_params {
-+ int32_t opt;
-+ int32_t otg_cap;
-+ int32_t dma_enable;
-+ int32_t dma_desc_enable;
-+ int32_t dma_burst_size;
-+ int32_t speed;
-+ int32_t host_support_fs_ls_low_power;
-+ int32_t host_ls_low_power_phy_clk;
-+ int32_t enable_dynamic_fifo;
-+ int32_t data_fifo_size;
-+ int32_t dev_rx_fifo_size;
-+ int32_t dev_nperio_tx_fifo_size;
-+ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
-+ int32_t host_rx_fifo_size;
-+ int32_t host_nperio_tx_fifo_size;
-+ int32_t host_perio_tx_fifo_size;
-+ int32_t max_transfer_size;
-+ int32_t max_packet_count;
-+ int32_t host_channels;
-+ int32_t dev_endpoints;
-+ int32_t phy_type;
-+ int32_t phy_utmi_width;
-+ int32_t phy_ulpi_ddr;
-+ int32_t phy_ulpi_ext_vbus;
-+ int32_t i2c_enable;
-+ int32_t ulpi_fs_ls;
-+ int32_t ts_dline;
-+ int32_t en_multiple_tx_fifo;
-+ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
-+ uint32_t thr_ctl;
-+ uint32_t tx_thr_length;
-+ uint32_t rx_thr_length;
-+ int32_t pti_enable;
-+ int32_t mpi_enable;
-+ int32_t lpm_enable;
-+ int32_t ic_usb_cap;
-+ int32_t ahb_thr_ratio;
-+ int32_t power_down;
-+ int32_t reload_ctl;
-+ int32_t dev_out_nak;
-+ int32_t cont_on_bna;
-+ int32_t ahb_single;
-+ int32_t otg_ver;
-+ int32_t adp_enable;
-+};
-+
-+static struct dwc_otg_driver_module_params dwc_otg_module_params = {
-+ .opt = -1,
-+ .otg_cap = -1,
-+ .dma_enable = -1,
-+ .dma_desc_enable = -1,
-+ .dma_burst_size = -1,
-+ .speed = -1,
-+ .host_support_fs_ls_low_power = -1,
-+ .host_ls_low_power_phy_clk = -1,
-+ .enable_dynamic_fifo = -1,
-+ .data_fifo_size = -1,
-+ .dev_rx_fifo_size = -1,
-+ .dev_nperio_tx_fifo_size = -1,
-+ .dev_perio_tx_fifo_size = {
-+ /* dev_perio_tx_fifo_size_1 */
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1
-+ /* 15 */
-+ },
-+ .host_rx_fifo_size = -1,
-+ .host_nperio_tx_fifo_size = -1,
-+ .host_perio_tx_fifo_size = -1,
-+ .max_transfer_size = -1,
-+ .max_packet_count = -1,
-+ .host_channels = -1,
-+ .dev_endpoints = -1,
-+ .phy_type = -1,
-+ .phy_utmi_width = -1,
-+ .phy_ulpi_ddr = -1,
-+ .phy_ulpi_ext_vbus = -1,
-+ .i2c_enable = -1,
-+ .ulpi_fs_ls = -1,
-+ .ts_dline = -1,
-+ .en_multiple_tx_fifo = -1,
-+ .dev_tx_fifo_size = {
-+ /* dev_tx_fifo_size */
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1,
-+ -1
-+ /* 15 */
-+ },
-+ .thr_ctl = -1,
-+ .tx_thr_length = -1,
-+ .rx_thr_length = -1,
-+ .pti_enable = -1,
-+ .mpi_enable = -1,
-+ .lpm_enable = 0,
-+ .ic_usb_cap = -1,
-+ .ahb_thr_ratio = -1,
-+ .power_down = -1,
-+ .reload_ctl = -1,
-+ .dev_out_nak = -1,
-+ .cont_on_bna = -1,
-+ .ahb_single = -1,
-+ .otg_ver = -1,
-+ .adp_enable = -1,
-+};
-+
-+//Global variable to switch the fiq fix on or off (declared in bcm2708.c)
-+extern bool fiq_fix_enable;
-+// Global variable to enable the split transaction fix
-+bool fiq_split_enable = true;
-+//Global variable to switch the nak holdoff on or off
-+bool nak_holdoff_enable = true;
-+
-+
-+/**
-+ * This function shows the Driver Version.
-+ */
-+static ssize_t version_show(struct device_driver *dev, char *buf)
-+{
-+ return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
-+ DWC_DRIVER_VERSION);
-+}
-+
-+static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
-+
-+/**
-+ * Global Debug Level Mask.
-+ */
-+uint32_t g_dbg_lvl = 0; /* OFF */
-+
-+/**
-+ * This function shows the driver Debug Level.
-+ */
-+static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
-+{
-+ return sprintf(buf, "0x%0x\n", g_dbg_lvl);
-+}
-+
-+/**
-+ * This function stores the driver Debug Level.
-+ */
-+static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
-+ size_t count)
-+{
-+ g_dbg_lvl = simple_strtoul(buf, NULL, 16);
-+ return count;
-+}
-+
-+static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
-+ dbg_level_store);
-+
-+/**
-+ * This function is called during module intialization
-+ * to pass module parameters to the DWC_OTG CORE.
-+ */
-+static int set_parameters(dwc_otg_core_if_t * core_if)
-+{
-+ int retval = 0;
-+ int i;
-+
-+ if (dwc_otg_module_params.otg_cap != -1) {
-+ retval +=
-+ dwc_otg_set_param_otg_cap(core_if,
-+ dwc_otg_module_params.otg_cap);
-+ }
-+ if (dwc_otg_module_params.dma_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_dma_enable(core_if,
-+ dwc_otg_module_params.
-+ dma_enable);
-+ }
-+ if (dwc_otg_module_params.dma_desc_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_dma_desc_enable(core_if,
-+ dwc_otg_module_params.
-+ dma_desc_enable);
-+ }
-+ if (dwc_otg_module_params.opt != -1) {
-+ retval +=
-+ dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
-+ }
-+ if (dwc_otg_module_params.dma_burst_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_dma_burst_size(core_if,
-+ dwc_otg_module_params.
-+ dma_burst_size);
-+ }
-+ if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
-+ retval +=
-+ dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
-+ dwc_otg_module_params.
-+ host_support_fs_ls_low_power);
-+ }
-+ if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
-+ retval +=
-+ dwc_otg_set_param_enable_dynamic_fifo(core_if,
-+ dwc_otg_module_params.
-+ enable_dynamic_fifo);
-+ }
-+ if (dwc_otg_module_params.data_fifo_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_data_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ data_fifo_size);
-+ }
-+ if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_dev_rx_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ dev_rx_fifo_size);
-+ }
-+ if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ dev_nperio_tx_fifo_size);
-+ }
-+ if (dwc_otg_module_params.host_rx_fifo_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_host_rx_fifo_size(core_if,
-+ dwc_otg_module_params.host_rx_fifo_size);
-+ }
-+ if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ host_nperio_tx_fifo_size);
-+ }
-+ if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ host_perio_tx_fifo_size);
-+ }
-+ if (dwc_otg_module_params.max_transfer_size != -1) {
-+ retval +=
-+ dwc_otg_set_param_max_transfer_size(core_if,
-+ dwc_otg_module_params.
-+ max_transfer_size);
-+ }
-+ if (dwc_otg_module_params.max_packet_count != -1) {
-+ retval +=
-+ dwc_otg_set_param_max_packet_count(core_if,
-+ dwc_otg_module_params.
-+ max_packet_count);
-+ }
-+ if (dwc_otg_module_params.host_channels != -1) {
-+ retval +=
-+ dwc_otg_set_param_host_channels(core_if,
-+ dwc_otg_module_params.
-+ host_channels);
-+ }
-+ if (dwc_otg_module_params.dev_endpoints != -1) {
-+ retval +=
-+ dwc_otg_set_param_dev_endpoints(core_if,
-+ dwc_otg_module_params.
-+ dev_endpoints);
-+ }
-+ if (dwc_otg_module_params.phy_type != -1) {
-+ retval +=
-+ dwc_otg_set_param_phy_type(core_if,
-+ dwc_otg_module_params.phy_type);
-+ }
-+ if (dwc_otg_module_params.speed != -1) {
-+ retval +=
-+ dwc_otg_set_param_speed(core_if,
-+ dwc_otg_module_params.speed);
-+ }
-+ if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
-+ retval +=
-+ dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
-+ dwc_otg_module_params.
-+ host_ls_low_power_phy_clk);
-+ }
-+ if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
-+ retval +=
-+ dwc_otg_set_param_phy_ulpi_ddr(core_if,
-+ dwc_otg_module_params.
-+ phy_ulpi_ddr);
-+ }
-+ if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
-+ retval +=
-+ dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
-+ dwc_otg_module_params.
-+ phy_ulpi_ext_vbus);
-+ }
-+ if (dwc_otg_module_params.phy_utmi_width != -1) {
-+ retval +=
-+ dwc_otg_set_param_phy_utmi_width(core_if,
-+ dwc_otg_module_params.
-+ phy_utmi_width);
-+ }
-+ if (dwc_otg_module_params.ulpi_fs_ls != -1) {
-+ retval +=
-+ dwc_otg_set_param_ulpi_fs_ls(core_if,
-+ dwc_otg_module_params.ulpi_fs_ls);
-+ }
-+ if (dwc_otg_module_params.ts_dline != -1) {
-+ retval +=
-+ dwc_otg_set_param_ts_dline(core_if,
-+ dwc_otg_module_params.ts_dline);
-+ }
-+ if (dwc_otg_module_params.i2c_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_i2c_enable(core_if,
-+ dwc_otg_module_params.
-+ i2c_enable);
-+ }
-+ if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
-+ retval +=
-+ dwc_otg_set_param_en_multiple_tx_fifo(core_if,
-+ dwc_otg_module_params.
-+ en_multiple_tx_fifo);
-+ }
-+ for (i = 0; i < 15; i++) {
-+ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
-+ retval +=
-+ dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ dev_perio_tx_fifo_size
-+ [i], i);
-+ }
-+ }
-+
-+ for (i = 0; i < 15; i++) {
-+ if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
-+ retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
-+ dwc_otg_module_params.
-+ dev_tx_fifo_size
-+ [i], i);
-+ }
-+ }
-+ if (dwc_otg_module_params.thr_ctl != -1) {
-+ retval +=
-+ dwc_otg_set_param_thr_ctl(core_if,
-+ dwc_otg_module_params.thr_ctl);
-+ }
-+ if (dwc_otg_module_params.mpi_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_mpi_enable(core_if,
-+ dwc_otg_module_params.
-+ mpi_enable);
-+ }
-+ if (dwc_otg_module_params.pti_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_pti_enable(core_if,
-+ dwc_otg_module_params.
-+ pti_enable);
-+ }
-+ if (dwc_otg_module_params.lpm_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_lpm_enable(core_if,
-+ dwc_otg_module_params.
-+ lpm_enable);
-+ }
-+ if (dwc_otg_module_params.ic_usb_cap != -1) {
-+ retval +=
-+ dwc_otg_set_param_ic_usb_cap(core_if,
-+ dwc_otg_module_params.
-+ ic_usb_cap);
-+ }
-+ if (dwc_otg_module_params.tx_thr_length != -1) {
-+ retval +=
-+ dwc_otg_set_param_tx_thr_length(core_if,
-+ dwc_otg_module_params.tx_thr_length);
-+ }
-+ if (dwc_otg_module_params.rx_thr_length != -1) {
-+ retval +=
-+ dwc_otg_set_param_rx_thr_length(core_if,
-+ dwc_otg_module_params.
-+ rx_thr_length);
-+ }
-+ if (dwc_otg_module_params.ahb_thr_ratio != -1) {
-+ retval +=
-+ dwc_otg_set_param_ahb_thr_ratio(core_if,
-+ dwc_otg_module_params.ahb_thr_ratio);
-+ }
-+ if (dwc_otg_module_params.power_down != -1) {
-+ retval +=
-+ dwc_otg_set_param_power_down(core_if,
-+ dwc_otg_module_params.power_down);
-+ }
-+ if (dwc_otg_module_params.reload_ctl != -1) {
-+ retval +=
-+ dwc_otg_set_param_reload_ctl(core_if,
-+ dwc_otg_module_params.reload_ctl);
-+ }
-+
-+ if (dwc_otg_module_params.dev_out_nak != -1) {
-+ retval +=
-+ dwc_otg_set_param_dev_out_nak(core_if,
-+ dwc_otg_module_params.dev_out_nak);
-+ }
-+
-+ if (dwc_otg_module_params.cont_on_bna != -1) {
-+ retval +=
-+ dwc_otg_set_param_cont_on_bna(core_if,
-+ dwc_otg_module_params.cont_on_bna);
-+ }
-+
-+ if (dwc_otg_module_params.ahb_single != -1) {
-+ retval +=
-+ dwc_otg_set_param_ahb_single(core_if,
-+ dwc_otg_module_params.ahb_single);
-+ }
-+
-+ if (dwc_otg_module_params.otg_ver != -1) {
-+ retval +=
-+ dwc_otg_set_param_otg_ver(core_if,
-+ dwc_otg_module_params.otg_ver);
-+ }
-+ if (dwc_otg_module_params.adp_enable != -1) {
-+ retval +=
-+ dwc_otg_set_param_adp_enable(core_if,
-+ dwc_otg_module_params.
-+ adp_enable);
-+ }
-+ return retval;
-+}
-+
-+/**
-+ * This function is the top level interrupt handler for the Common
-+ * (Device and host modes) interrupts.
-+ */
-+static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
-+{
-+ int32_t retval = IRQ_NONE;
-+
-+ retval = dwc_otg_handle_common_intr(dev);
-+ if (retval != 0) {
-+ S3C2410X_CLEAR_EINTPEND();
-+ }
-+ return IRQ_RETVAL(retval);
-+}
-+
-+/**
-+ * This function is called when a lm_device is unregistered with the
-+ * dwc_otg_driver. This happens, for example, when the rmmod command is
-+ * executed. The device may or may not be electrically present. If it is
-+ * present, the driver stops device processing. Any resources used on behalf
-+ * of this device are freed.
-+ *
-+ * @param _dev
-+ */
-+#ifdef LM_INTERFACE
-+#define REM_RETVAL(n)
-+static void dwc_otg_driver_remove( struct lm_device *_dev )
-+{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
-+#elif defined(PCI_INTERFACE)
-+#define REM_RETVAL(n)
-+static void dwc_otg_driver_remove( struct pci_dev *_dev )
-+{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
-+#elif defined(PLATFORM_INTERFACE)
-+#define REM_RETVAL(n) n
-+static int dwc_otg_driver_remove( struct platform_device *_dev )
-+{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
-+#endif
-+
-+ DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
-+
-+ if (!otg_dev) {
-+ /* Memory allocation for the dwc_otg_device failed. */
-+ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
-+ return REM_RETVAL(-ENOMEM);
-+ }
-+#ifndef DWC_DEVICE_ONLY
-+ if (otg_dev->hcd) {
-+ hcd_remove(_dev);
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
-+ return REM_RETVAL(-EINVAL);
-+ }
-+#endif
-+
-+#ifndef DWC_HOST_ONLY
-+ if (otg_dev->pcd) {
-+ pcd_remove(_dev);
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__);
-+ return REM_RETVAL(-EINVAL);
-+ }
-+#endif
-+ /*
-+ * Free the IRQ
-+ */
-+ if (otg_dev->common_irq_installed) {
-+#ifdef PLATFORM_INTERFACE
-+ free_irq(platform_get_irq(_dev, 0), otg_dev);
-+#else
-+ free_irq(_dev->irq, otg_dev);
-+#endif
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__);
-+ return REM_RETVAL(-ENXIO);
-+ }
-+
-+ if (otg_dev->core_if) {
-+ dwc_otg_cil_remove(otg_dev->core_if);
-+ } else {
-+ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__);
-+ return REM_RETVAL(-ENXIO);
-+ }
-+
-+ /*
-+ * Remove the device attributes
-+ */
-+ dwc_otg_attr_remove(_dev);
-+
-+ /*
-+ * Return the memory.
-+ */
-+ if (otg_dev->os_dep.base) {
-+ iounmap(otg_dev->os_dep.base);
-+ }
-+ DWC_FREE(otg_dev);
-+
-+ /*
-+ * Clear the drvdata pointer.
-+ */
-+#ifdef LM_INTERFACE
-+ lm_set_drvdata(_dev, 0);
-+#elif defined(PCI_INTERFACE)
-+ release_mem_region(otg_dev->os_dep.rsrc_start,
-+ otg_dev->os_dep.rsrc_len);
-+ pci_set_drvdata(_dev, 0);
-+#elif defined(PLATFORM_INTERFACE)
-+ platform_set_drvdata(_dev, 0);
-+#endif
-+ return REM_RETVAL(0);
-+}
-+
-+/**
-+ * This function is called when an lm_device is bound to a
-+ * dwc_otg_driver. It creates the driver components required to
-+ * control the device (CIL, HCD, and PCD) and it initializes the
-+ * device. The driver components are stored in a dwc_otg_device
-+ * structure. A reference to the dwc_otg_device is saved in the
-+ * lm_device. This allows the driver to access the dwc_otg_device
-+ * structure on subsequent calls to driver methods for this device.
-+ *
-+ * @param _dev Bus device
-+ */
-+static int dwc_otg_driver_probe(
-+#ifdef LM_INTERFACE
-+ struct lm_device *_dev
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *_dev,
-+ const struct pci_device_id *id
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *_dev
-+#endif
-+ )
-+{
-+ int retval = 0;
-+ dwc_otg_device_t *dwc_otg_device;
-+ int devirq;
-+
-+ dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
-+#ifdef LM_INTERFACE
-+ dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
-+#elif defined(PCI_INTERFACE)
-+ if (!id) {
-+ DWC_ERROR("Invalid pci_device_id %p", id);
-+ return -EINVAL;
-+ }
-+
-+ if (!_dev || (pci_enable_device(_dev) < 0)) {
-+ DWC_ERROR("Invalid pci_device %p", _dev);
-+ return -ENODEV;
-+ }
-+ dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
-+ /* other stuff needed as well? */
-+
-+#elif defined(PLATFORM_INTERFACE)
-+ dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n",
-+ (unsigned)_dev->resource->start,
-+ (unsigned)(_dev->resource->end - _dev->resource->start));
-+#endif
-+
-+ dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t));
-+
-+ if (!dwc_otg_device) {
-+ dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
-+ return -ENOMEM;
-+ }
-+
-+ memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
-+ dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF;
-+
-+ /*
-+ * Map the DWC_otg Core memory into virtual address space.
-+ */
-+#ifdef LM_INTERFACE
-+ dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K);
-+
-+ if (!dwc_otg_device->os_dep.base) {
-+ dev_err(&_dev->dev, "ioremap() failed\n");
-+ DWC_FREE(dwc_otg_device);
-+ return -ENOMEM;
-+ }
-+ dev_dbg(&_dev->dev, "base=0x%08x\n",
-+ (unsigned)dwc_otg_device->os_dep.base);
-+#elif defined(PCI_INTERFACE)
-+ _dev->current_state = PCI_D0;
-+ _dev->dev.power.power_state = PMSG_ON;
-+
-+ if (!_dev->irq) {
-+ DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!",
-+ pci_name(_dev));
-+ iounmap(dwc_otg_device->os_dep.base);
-+ DWC_FREE(dwc_otg_device);
-+ return -ENODEV;
-+ }
-+
-+ dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0);
-+ dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0);
-+ DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n",
-+ (unsigned)dwc_otg_device->os_dep.rsrc_start,
-+ (unsigned)dwc_otg_device->os_dep.rsrc_len);
-+ if (!request_mem_region
-+ (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len,
-+ "dwc_otg")) {
-+ dev_dbg(&_dev->dev, "error requesting memory\n");
-+ iounmap(dwc_otg_device->os_dep.base);
-+ DWC_FREE(dwc_otg_device);
-+ return -EFAULT;
-+ }
-+
-+ dwc_otg_device->os_dep.base =
-+ ioremap_nocache(dwc_otg_device->os_dep.rsrc_start,
-+ dwc_otg_device->os_dep.rsrc_len);
-+ if (dwc_otg_device->os_dep.base == NULL) {
-+ dev_dbg(&_dev->dev, "error mapping memory\n");
-+ release_mem_region(dwc_otg_device->os_dep.rsrc_start,
-+ dwc_otg_device->os_dep.rsrc_len);
-+ iounmap(dwc_otg_device->os_dep.base);
-+ DWC_FREE(dwc_otg_device);
-+ return -EFAULT;
-+ }
-+ dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n",
-+ dwc_otg_device->os_dep.base);
-+ dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base;
-+ dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n",
-+ dwc_otg_device->os_dep.base);
-+ dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
-+ (unsigned)dwc_otg_device->os_dep.rsrc_start,
-+ dwc_otg_device->os_dep.base);
-+
-+ pci_set_master(_dev);
-+ pci_set_drvdata(_dev, dwc_otg_device);
-+#elif defined(PLATFORM_INTERFACE)
-+ DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n",
-+ _dev->resource->start,
-+ _dev->resource->end - _dev->resource->start + 1);
-+#if 1
-+ if (!request_mem_region(_dev->resource[0].start,
-+ _dev->resource[0].end - _dev->resource[0].start + 1,
-+ "dwc_otg")) {
-+ dev_dbg(&_dev->dev, "error reserving mapped memory\n");
-+ retval = -EFAULT;
-+ goto fail;
-+ }
-+
-+ dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start,
-+ _dev->resource[0].end -
-+ _dev->resource[0].start+1);
-+ if (fiq_fix_enable)
-+ {
-+ if (!request_mem_region(_dev->resource[1].start,
-+ _dev->resource[1].end - _dev->resource[1].start + 1,
-+ "dwc_otg")) {
-+ dev_dbg(&_dev->dev, "error reserving mapped memory\n");
-+ retval = -EFAULT;
-+ goto fail;
-+ }
-+
-+ dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
-+ _dev->resource[1].end -
-+ _dev->resource[1].start + 1);
-+ dummy_send = (void *) kmalloc(16, GFP_ATOMIC);
-+ }
-+
-+#else
-+ {
-+ struct map_desc desc = {
-+ .virtual = IO_ADDRESS((unsigned)_dev->resource->start),
-+ .pfn = __phys_to_pfn((unsigned)_dev->resource->start),
-+ .length = SZ_128K,
-+ .type = MT_DEVICE
-+ };
-+ iotable_init(&desc, 1);
-+ dwc_otg_device->os_dep.base = (void *)desc.virtual;
-+ }
-+#endif
-+ if (!dwc_otg_device->os_dep.base) {
-+ dev_err(&_dev->dev, "ioremap() failed\n");
-+ retval = -ENOMEM;
-+ goto fail;
-+ }
-+ dev_dbg(&_dev->dev, "base=0x%08x\n",
-+ (unsigned)dwc_otg_device->os_dep.base);
-+#endif
-+
-+ /*
-+ * Initialize driver data to point to the global DWC_otg
-+ * Device structure.
-+ */
-+#ifdef LM_INTERFACE
-+ lm_set_drvdata(_dev, dwc_otg_device);
-+#elif defined(PLATFORM_INTERFACE)
-+ platform_set_drvdata(_dev, dwc_otg_device);
-+#endif
-+ dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
-+
-+ dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base);
-+ DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n",
-+ dwc_otg_device, dwc_otg_device->core_if);//GRAYG
-+
-+ if (!dwc_otg_device->core_if) {
-+ dev_err(&_dev->dev, "CIL initialization failed!\n");
-+ retval = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ dev_dbg(&_dev->dev, "Calling get_gsnpsid\n");
-+ /*
-+ * Attempt to ensure this device is really a DWC_otg Controller.
-+ * Read and verify the SNPSID register contents. The value should be
-+ * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
-+ * as in "OTG version 2.XX" or "OTG version 3.XX".
-+ */
-+
-+ if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) &&
-+ ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) {
-+ dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
-+ dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
-+ retval = -EINVAL;
-+ goto fail;
-+ }
-+
-+ /*
-+ * Validate parameter values.
-+ */
-+ dev_dbg(&_dev->dev, "Calling set_parameters\n");
-+ if (set_parameters(dwc_otg_device->core_if)) {
-+ retval = -EINVAL;
-+ goto fail;
-+ }
-+
-+ /*
-+ * Create Device Attributes in sysfs
-+ */
-+ dev_dbg(&_dev->dev, "Calling attr_create\n");
-+ dwc_otg_attr_create(_dev);
-+
-+ /*
-+ * Disable the global interrupt until all the interrupt
-+ * handlers are installed.
-+ */
-+ dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n");
-+ dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
-+
-+ /*
-+ * Install the interrupt handler for the common interrupts before
-+ * enabling common interrupts in core_init below.
-+ */
-+
-+#if defined(PLATFORM_INTERFACE)
-+ devirq = platform_get_irq(_dev, 0);
-+#else
-+ devirq = _dev->irq;
-+#endif
-+ DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
-+ devirq);
-+ dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq);
-+ retval = request_irq(devirq, dwc_otg_common_irq,
-+ IRQF_SHARED,
-+ "dwc_otg", dwc_otg_device);
-+ if (retval) {
-+ DWC_ERROR("request of irq%d failed\n", devirq);
-+ retval = -EBUSY;
-+ goto fail;
-+ } else {
-+ dwc_otg_device->common_irq_installed = 1;
-+ }
-+
-+#ifndef IRQF_TRIGGER_LOW
-+#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
-+ dev_dbg(&_dev->dev, "Calling set_irq_type\n");
-+ set_irq_type(devirq,
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
-+ IRQT_LOW
-+#else
-+ IRQ_TYPE_LEVEL_LOW
-+#endif
-+ );
-+#endif
-+#endif /*IRQF_TRIGGER_LOW*/
-+
-+ /*
-+ * Initialize the DWC_otg core.
-+ */
-+ dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n");
-+ dwc_otg_core_init(dwc_otg_device->core_if);
-+
-+#ifndef DWC_HOST_ONLY
-+ /*
-+ * Initialize the PCD
-+ */
-+ dev_dbg(&_dev->dev, "Calling pcd_init\n");
-+ retval = pcd_init(_dev);
-+ if (retval != 0) {
-+ DWC_ERROR("pcd_init failed\n");
-+ dwc_otg_device->pcd = NULL;
-+ goto fail;
-+ }
-+#endif
-+#ifndef DWC_DEVICE_ONLY
-+ /*
-+ * Initialize the HCD
-+ */
-+ dev_dbg(&_dev->dev, "Calling hcd_init\n");
-+ retval = hcd_init(_dev);
-+ if (retval != 0) {
-+ DWC_ERROR("hcd_init failed\n");
-+ dwc_otg_device->hcd = NULL;
-+ goto fail;
-+ }
-+#endif
-+ /* Recover from drvdata having been overwritten by hcd_init() */
-+#ifdef LM_INTERFACE
-+ lm_set_drvdata(_dev, dwc_otg_device);
-+#elif defined(PLATFORM_INTERFACE)
-+ platform_set_drvdata(_dev, dwc_otg_device);
-+#elif defined(PCI_INTERFACE)
-+ pci_set_drvdata(_dev, dwc_otg_device);
-+ dwc_otg_device->os_dep.pcidev = _dev;
-+#endif
-+
-+ /*
-+ * Enable the global interrupt after all the interrupt
-+ * handlers are installed if there is no ADP support else
-+ * perform initial actions required for Internal ADP logic.
-+ */
-+ if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) {
-+ dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n");
-+ dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
-+ dev_dbg(&_dev->dev, "Done\n");
-+ } else
-+ dwc_otg_adp_start(dwc_otg_device->core_if,
-+ dwc_otg_is_host_mode(dwc_otg_device->core_if));
-+
-+ return 0;
-+
-+fail:
-+ dwc_otg_driver_remove(_dev);
-+ return retval;
-+}
-+
-+/**
-+ * This structure defines the methods to be called by a bus driver
-+ * during the lifecycle of a device on that bus. Both drivers and
-+ * devices are registered with a bus driver. The bus driver matches
-+ * devices to drivers based on information in the device and driver
-+ * structures.
-+ *
-+ * The probe function is called when the bus driver matches a device
-+ * to this driver. The remove function is called when a device is
-+ * unregistered with the bus driver.
-+ */
-+#ifdef LM_INTERFACE
-+static struct lm_driver dwc_otg_driver = {
-+ .drv = {.name = (char *)dwc_driver_name,},
-+ .probe = dwc_otg_driver_probe,
-+ .remove = dwc_otg_driver_remove,
-+ // 'suspend' and 'resume' absent
-+};
-+#elif defined(PCI_INTERFACE)
-+static const struct pci_device_id pci_ids[] = { {
-+ PCI_DEVICE(0x16c3, 0xabcd),
-+ .driver_data =
-+ (unsigned long)0xdeadbeef,
-+ }, { /* end: all zeroes */ }
-+};
-+
-+MODULE_DEVICE_TABLE(pci, pci_ids);
-+
-+/* pci driver glue; this is a "new style" PCI driver module */
-+static struct pci_driver dwc_otg_driver = {
-+ .name = "dwc_otg",
-+ .id_table = pci_ids,
-+
-+ .probe = dwc_otg_driver_probe,
-+ .remove = dwc_otg_driver_remove,
-+
-+ .driver = {
-+ .name = (char *)dwc_driver_name,
-+ },
-+};
-+#elif defined(PLATFORM_INTERFACE)
-+static struct platform_device_id platform_ids[] = {
-+ {
-+ .name = "bcm2708_usb",
-+ .driver_data = (kernel_ulong_t) 0xdeadbeef,
-+ },
-+ { /* end: all zeroes */ }
-+};
-+MODULE_DEVICE_TABLE(platform, platform_ids);
-+
-+static struct platform_driver dwc_otg_driver = {
-+ .driver = {
-+ .name = (char *)dwc_driver_name,
-+ },
-+ .id_table = platform_ids,
-+
-+ .probe = dwc_otg_driver_probe,
-+ .remove = dwc_otg_driver_remove,
-+ // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early'
-+};
-+#endif
-+
-+/**
-+ * This function is called when the dwc_otg_driver is installed with the
-+ * insmod command. It registers the dwc_otg_driver structure with the
-+ * appropriate bus driver. This will cause the dwc_otg_driver_probe function
-+ * to be called. In addition, the bus driver will automatically expose
-+ * attributes defined for the device and driver in the special sysfs file
-+ * system.
-+ *
-+ * @return
-+ */
-+static int __init dwc_otg_driver_init(void)
-+{
-+ int retval = 0;
-+ int error;
-+ struct device_driver *drv;
-+
-+ if(fiq_split_enable && !fiq_fix_enable) {
-+ printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n");
-+ fiq_fix_enable = 1;
-+ }
-+
-+ printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
-+ DWC_DRIVER_VERSION,
-+#ifdef LM_INTERFACE
-+ "logicmodule");
-+ retval = lm_driver_register(&dwc_otg_driver);
-+ drv = &dwc_otg_driver.drv;
-+#elif defined(PCI_INTERFACE)
-+ "pci");
-+ retval = pci_register_driver(&dwc_otg_driver);
-+ drv = &dwc_otg_driver.driver;
-+#elif defined(PLATFORM_INTERFACE)
-+ "platform");
-+ retval = platform_driver_register(&dwc_otg_driver);
-+ drv = &dwc_otg_driver.driver;
-+#endif
-+ if (retval < 0) {
-+ printk(KERN_ERR "%s retval=%d\n", __func__, retval);
-+ return retval;
-+ }
-+ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled");
-+ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled");
-+ printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled");
-+
-+ error = driver_create_file(drv, &driver_attr_version);
-+#ifdef DEBUG
-+ error = driver_create_file(drv, &driver_attr_debuglevel);
-+#endif
-+ return retval;
-+}
-+
-+module_init(dwc_otg_driver_init);
-+
-+/**
-+ * This function is called when the driver is removed from the kernel
-+ * with the rmmod command. The driver unregisters itself with its bus
-+ * driver.
-+ *
-+ */
-+static void __exit dwc_otg_driver_cleanup(void)
-+{
-+ printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
-+
-+#ifdef LM_INTERFACE
-+ driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
-+ driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
-+ lm_driver_unregister(&dwc_otg_driver);
-+#elif defined(PCI_INTERFACE)
-+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
-+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
-+ pci_unregister_driver(&dwc_otg_driver);
-+#elif defined(PLATFORM_INTERFACE)
-+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
-+ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
-+ platform_driver_unregister(&dwc_otg_driver);
-+#endif
-+
-+ printk(KERN_INFO "%s module removed\n", dwc_driver_name);
-+}
-+
-+module_exit(dwc_otg_driver_cleanup);
-+
-+MODULE_DESCRIPTION(DWC_DRIVER_DESC);
-+MODULE_AUTHOR("Synopsys Inc.");
-+MODULE_LICENSE("GPL");
-+
-+module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
-+MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
-+module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
-+MODULE_PARM_DESC(opt, "OPT Mode");
-+module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
-+MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
-+
-+module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
-+ 0444);
-+MODULE_PARM_DESC(dma_desc_enable,
-+ "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
-+
-+module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
-+ 0444);
-+MODULE_PARM_DESC(dma_burst_size,
-+ "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
-+module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
-+MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
-+module_param_named(host_support_fs_ls_low_power,
-+ dwc_otg_module_params.host_support_fs_ls_low_power, int,
-+ 0444);
-+MODULE_PARM_DESC(host_support_fs_ls_low_power,
-+ "Support Low Power w/FS or LS 0=Support 1=Don't Support");
-+module_param_named(host_ls_low_power_phy_clk,
-+ dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
-+MODULE_PARM_DESC(host_ls_low_power_phy_clk,
-+ "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
-+module_param_named(enable_dynamic_fifo,
-+ dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
-+MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
-+module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
-+ 0444);
-+MODULE_PARM_DESC(data_fifo_size,
-+ "Total number of words in the data FIFO memory 32-32768");
-+module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
-+ int, 0444);
-+MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
-+module_param_named(dev_nperio_tx_fifo_size,
-+ dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
-+MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
-+ "Number of words in the non-periodic Tx FIFO 16-32768");
-+module_param_named(dev_perio_tx_fifo_size_1,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_2,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_3,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_4,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_5,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_6,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_7,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_8,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_9,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_10,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_11,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_12,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_13,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_14,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(dev_perio_tx_fifo_size_15,
-+ dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
-+MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
-+ "Number of words in the periodic Tx FIFO 4-768");
-+module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
-+ int, 0444);
-+MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
-+module_param_named(host_nperio_tx_fifo_size,
-+ dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
-+MODULE_PARM_DESC(host_nperio_tx_fifo_size,
-+ "Number of words in the non-periodic Tx FIFO 16-32768");
-+module_param_named(host_perio_tx_fifo_size,
-+ dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
-+MODULE_PARM_DESC(host_perio_tx_fifo_size,
-+ "Number of words in the host periodic Tx FIFO 16-32768");
-+module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
-+ int, 0444);
-+/** @todo Set the max to 512K, modify checks */
-+MODULE_PARM_DESC(max_transfer_size,
-+ "The maximum transfer size supported in bytes 2047-65535");
-+module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
-+ int, 0444);
-+MODULE_PARM_DESC(max_packet_count,
-+ "The maximum number of packets in a transfer 15-511");
-+module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
-+ 0444);
-+MODULE_PARM_DESC(host_channels,
-+ "The number of host channel registers to use 1-16");
-+module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
-+ 0444);
-+MODULE_PARM_DESC(dev_endpoints,
-+ "The number of endpoints in addition to EP0 available for device mode 1-15");
-+module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
-+MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
-+module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
-+ 0444);
-+MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
-+module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
-+MODULE_PARM_DESC(phy_ulpi_ddr,
-+ "ULPI at double or single data rate 0=Single 1=Double");
-+module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
-+ int, 0444);
-+MODULE_PARM_DESC(phy_ulpi_ext_vbus,
-+ "ULPI PHY using internal or external vbus 0=Internal");
-+module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
-+MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
-+module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
-+MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
-+module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
-+MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
-+module_param_named(debug, g_dbg_lvl, int, 0444);
-+MODULE_PARM_DESC(debug, "");
-+
-+module_param_named(en_multiple_tx_fifo,
-+ dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
-+MODULE_PARM_DESC(en_multiple_tx_fifo,
-+ "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
-+module_param_named(dev_tx_fifo_size_1,
-+ dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_2,
-+ dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_3,
-+ dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_4,
-+ dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_5,
-+ dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_6,
-+ dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_7,
-+ dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_8,
-+ dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_9,
-+ dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_10,
-+ dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_11,
-+ dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_12,
-+ dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_13,
-+ dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_14,
-+ dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
-+module_param_named(dev_tx_fifo_size_15,
-+ dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
-+MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
-+
-+module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
-+MODULE_PARM_DESC(thr_ctl,
-+ "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
-+module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
-+ 0444);
-+MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
-+module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
-+ 0444);
-+MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
-+
-+module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
-+module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
-+module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
-+MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
-+module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
-+MODULE_PARM_DESC(ic_usb_cap,
-+ "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
-+module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int,
-+ 0444);
-+MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
-+module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444);
-+MODULE_PARM_DESC(power_down, "Power Down Mode");
-+module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444);
-+MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control");
-+module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444);
-+MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK");
-+module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444);
-+MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA");
-+module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444);
-+MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support");
-+module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
-+MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
-+module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
-+MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
-+module_param(microframe_schedule, bool, 0444);
-+MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
-+
-+module_param(fiq_fix_enable, bool, 0444);
-+MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix");
-+module_param(nak_holdoff_enable, bool, 0444);
-+MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff");
-+module_param(fiq_split_enable, bool, 0444);
-+MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions");
-+
-+/** @page "Module Parameters"
-+ *
-+ * The following parameters may be specified when starting the module.
-+ * These parameters define how the DWC_otg controller should be
-+ * configured. Parameter values are passed to the CIL initialization
-+ * function dwc_otg_cil_init
-+ *
-+ * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
-+ *
-+
-+ <table>
-+ <tr><td>Parameter Name</td><td>Meaning</td></tr>
-+
-+ <tr>
-+ <td>otg_cap</td>
-+ <td>Specifies the OTG capabilities. The driver will automatically detect the
-+ value for this parameter if none is specified.
-+ - 0: HNP and SRP capable (default, if available)
-+ - 1: SRP Only capable
-+ - 2: No HNP/SRP capable
-+ </td></tr>
-+
-+ <tr>
-+ <td>dma_enable</td>
-+ <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: Slave
-+ - 1: DMA (default, if available)
-+ </td></tr>
-+
-+ <tr>
-+ <td>dma_burst_size</td>
-+ <td>The DMA Burst size (applicable only for External DMA Mode).
-+ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
-+ </td></tr>
-+
-+ <tr>
-+ <td>speed</td>
-+ <td>Specifies the maximum speed of operation in host and device mode. The
-+ actual speed depends on the speed of the attached device and the value of
-+ phy_type.
-+ - 0: High Speed (default)
-+ - 1: Full Speed
-+ </td></tr>
-+
-+ <tr>
-+ <td>host_support_fs_ls_low_power</td>
-+ <td>Specifies whether low power mode is supported when attached to a Full
-+ Speed or Low Speed device in host mode.
-+ - 0: Don't support low power mode (default)
-+ - 1: Support low power mode
-+ </td></tr>
-+
-+ <tr>
-+ <td>host_ls_low_power_phy_clk</td>
-+ <td>Specifies the PHY clock rate in low power mode when connected to a Low
-+ Speed device in host mode. This parameter is applicable only if
-+ HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
-+ - 0: 48 MHz (default)
-+ - 1: 6 MHz
-+ </td></tr>
-+
-+ <tr>
-+ <td>enable_dynamic_fifo</td>
-+ <td> Specifies whether FIFOs may be resized by the driver software.
-+ - 0: Use cC FIFO size parameters
-+ - 1: Allow dynamic FIFO sizing (default)
-+ </td></tr>
-+
-+ <tr>
-+ <td>data_fifo_size</td>
-+ <td>Total number of 4-byte words in the data FIFO memory. This memory
-+ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
-+ - Values: 32 to 32768 (default 8192)
-+
-+ Note: The total FIFO memory depth in the FPGA configuration is 8192.
-+ </td></tr>
-+
-+ <tr>
-+ <td>dev_rx_fifo_size</td>
-+ <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
-+ FIFO sizing is enabled.
-+ - Values: 16 to 32768 (default 1064)
-+ </td></tr>
-+
-+ <tr>
-+ <td>dev_nperio_tx_fifo_size</td>
-+ <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
-+ dynamic FIFO sizing is enabled.
-+ - Values: 16 to 32768 (default 1024)
-+ </td></tr>
-+
-+ <tr>
-+ <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
-+ <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
-+ when dynamic FIFO sizing is enabled.
-+ - Values: 4 to 768 (default 256)
-+ </td></tr>
-+
-+ <tr>
-+ <td>host_rx_fifo_size</td>
-+ <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
-+ sizing is enabled.
-+ - Values: 16 to 32768 (default 1024)
-+ </td></tr>
-+
-+ <tr>
-+ <td>host_nperio_tx_fifo_size</td>
-+ <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
-+ dynamic FIFO sizing is enabled in the core.
-+ - Values: 16 to 32768 (default 1024)
-+ </td></tr>
-+
-+ <tr>
-+ <td>host_perio_tx_fifo_size</td>
-+ <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
-+ sizing is enabled.
-+ - Values: 16 to 32768 (default 1024)
-+ </td></tr>
-+
-+ <tr>
-+ <td>max_transfer_size</td>
-+ <td>The maximum transfer size supported in bytes.
-+ - Values: 2047 to 65,535 (default 65,535)
-+ </td></tr>
-+
-+ <tr>
-+ <td>max_packet_count</td>
-+ <td>The maximum number of packets in a transfer.
-+ - Values: 15 to 511 (default 511)
-+ </td></tr>
-+
-+ <tr>
-+ <td>host_channels</td>
-+ <td>The number of host channel registers to use.
-+ - Values: 1 to 16 (default 12)
-+
-+ Note: The FPGA configuration supports a maximum of 12 host channels.
-+ </td></tr>
-+
-+ <tr>
-+ <td>dev_endpoints</td>
-+ <td>The number of endpoints in addition to EP0 available for device mode
-+ operations.
-+ - Values: 1 to 15 (default 6 IN and OUT)
-+
-+ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
-+ addition to EP0.
-+ </td></tr>
-+
-+ <tr>
-+ <td>phy_type</td>
-+ <td>Specifies the type of PHY interface to use. By default, the driver will
-+ automatically detect the phy_type.
-+ - 0: Full Speed
-+ - 1: UTMI+ (default, if available)
-+ - 2: ULPI
-+ </td></tr>
-+
-+ <tr>
-+ <td>phy_utmi_width</td>
-+ <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
-+ phy_type of UTMI+. Also, this parameter is applicable only if the
-+ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
-+ core has been configured to work at either data path width.
-+ - Values: 8 or 16 bits (default 16)
-+ </td></tr>
-+
-+ <tr>
-+ <td>phy_ulpi_ddr</td>
-+ <td>Specifies whether the ULPI operates at double or single data rate. This
-+ parameter is only applicable if phy_type is ULPI.
-+ - 0: single data rate ULPI interface with 8 bit wide data bus (default)
-+ - 1: double data rate ULPI interface with 4 bit wide data bus
-+ </td></tr>
-+
-+ <tr>
-+ <td>i2c_enable</td>
-+ <td>Specifies whether to use the I2C interface for full speed PHY. This
-+ parameter is only applicable if PHY_TYPE is FS.
-+ - 0: Disabled (default)
-+ - 1: Enabled
-+ </td></tr>
-+
-+ <tr>
-+ <td>ulpi_fs_ls</td>
-+ <td>Specifies whether to use ULPI FS/LS mode only.
-+ - 0: Disabled (default)
-+ - 1: Enabled
-+ </td></tr>
-+
-+ <tr>
-+ <td>ts_dline</td>
-+ <td>Specifies whether term select D-Line pulsing for all PHYs is enabled.
-+ - 0: Disabled (default)
-+ - 1: Enabled
-+ </td></tr>
-+
-+ <tr>
-+ <td>en_multiple_tx_fifo</td>
-+ <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: Disabled
-+ - 1: Enabled (default, if available)
-+ </td></tr>
-+
-+ <tr>
-+ <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
-+ <td>Number of 4-byte words in each of the Tx FIFOs in device mode
-+ when dynamic FIFO sizing is enabled.
-+ - Values: 4 to 768 (default 256)
-+ </td></tr>
-+
-+ <tr>
-+ <td>tx_thr_length</td>
-+ <td>Transmit Threshold length in 32 bit double words
-+ - Values: 8 to 128 (default 64)
-+ </td></tr>
-+
-+ <tr>
-+ <td>rx_thr_length</td>
-+ <td>Receive Threshold length in 32 bit double words
-+ - Values: 8 to 128 (default 64)
-+ </td></tr>
-+
-+<tr>
-+ <td>thr_ctl</td>
-+ <td>Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of
-+ this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and
-+ Rx transfers accordingly.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - Values: 0 to 7 (default 0)
-+ Bit values indicate:
-+ - 0: Thresholding disabled
-+ - 1: Thresholding enabled
-+ </td></tr>
-+
-+<tr>
-+ <td>dma_desc_enable</td>
-+ <td>Specifies whether to enable Descriptor DMA mode.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: Descriptor DMA disabled
-+ - 1: Descriptor DMA (default, if available)
-+ </td></tr>
-+
-+<tr>
-+ <td>mpi_enable</td>
-+ <td>Specifies whether to enable MPI enhancement mode.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: MPI disabled (default)
-+ - 1: MPI enable
-+ </td></tr>
-+
-+<tr>
-+ <td>pti_enable</td>
-+ <td>Specifies whether to enable PTI enhancement support.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: PTI disabled (default)
-+ - 1: PTI enable
-+ </td></tr>
-+
-+<tr>
-+ <td>lpm_enable</td>
-+ <td>Specifies whether to enable LPM support.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: LPM disabled
-+ - 1: LPM enable (default, if available)
-+ </td></tr>
-+
-+<tr>
-+ <td>ic_usb_cap</td>
-+ <td>Specifies whether to enable IC_USB capability.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: IC_USB disabled (default, if available)
-+ - 1: IC_USB enable
-+ </td></tr>
-+
-+<tr>
-+ <td>ahb_thr_ratio</td>
-+ <td>Specifies AHB Threshold ratio.
-+ - Values: 0 to 3 (default 0)
-+ </td></tr>
-+
-+<tr>
-+ <td>power_down</td>
-+ <td>Specifies Power Down(Hibernation) Mode.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: Power Down disabled (default)
-+ - 2: Power Down enabled
-+ </td></tr>
-+
-+ <tr>
-+ <td>reload_ctl</td>
-+ <td>Specifies whether dynamic reloading of the HFIR register is allowed during
-+ run time. The driver will automatically detect the value for this parameter if
-+ none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0
-+ the core might misbehave.
-+ - 0: Reload Control disabled (default)
-+ - 1: Reload Control enabled
-+ </td></tr>
-+
-+ <tr>
-+ <td>dev_out_nak</td>
-+ <td>Specifies whether Device OUT NAK enhancement enabled or no.
-+ The driver will automatically detect the value for this parameter if
-+ none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
-+ - 0: The core does not set NAK after Bulk OUT transfer complete (default)
-+ - 1: The core sets NAK after Bulk OUT transfer complete
-+ </td></tr>
-+
-+ <tr>
-+ <td>cont_on_bna</td>
-+ <td>Specifies whether Enable Continue on BNA enabled or no.
-+ After receiving BNA interrupt the core disables the endpoint,when the
-+ endpoint is re-enabled by the application the
-+ - 0: Core starts processing from the DOEPDMA descriptor (default)
-+ - 1: Core starts processing from the descriptor which received the BNA.
-+ This parameter is valid only when OTG_EN_DESC_DMA == 1b1.
-+ </td></tr>
-+
-+ <tr>
-+ <td>ahb_single</td>
-+ <td>This bit when programmed supports SINGLE transfers for remainder data
-+ in a transfer for DMA mode of operation.
-+ - 0: The remainder data will be sent using INCR burst size (default)
-+ - 1: The remainder data will be sent using SINGLE burst size.
-+ </td></tr>
-+
-+<tr>
-+ <td>adp_enable</td>
-+ <td>Specifies whether ADP feature is enabled.
-+ The driver will automatically detect the value for this parameter if none is
-+ specified.
-+ - 0: ADP feature disabled (default)
-+ - 1: ADP feature enabled
-+ </td></tr>
-+
-+ <tr>
-+ <td>otg_ver</td>
-+ <td>Specifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3
-+ USB OTG device.
-+ - 0: OTG 2.0 support disabled (default)
-+ - 1: OTG 2.0 support enabled
-+ </td></tr>
-+
-+*/
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_driver.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_driver.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_driver.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_driver.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,86 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
-+ * $Revision: #19 $
-+ * $Date: 2010/11/15 $
-+ * $Change: 1627671 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#ifndef __DWC_OTG_DRIVER_H__
-+#define __DWC_OTG_DRIVER_H__
-+
-+/** @file
-+ * This file contains the interface to the Linux driver.
-+ */
-+#include "dwc_otg_os_dep.h"
-+#include "dwc_otg_core_if.h"
-+
-+/* Type declarations */
-+struct dwc_otg_pcd;
-+struct dwc_otg_hcd;
-+
-+/**
-+ * This structure is a wrapper that encapsulates the driver components used to
-+ * manage a single DWC_otg controller.
-+ */
-+typedef struct dwc_otg_device {
-+ /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE
-+ * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD
-+ * require this. */
-+ struct os_dependent os_dep;
-+
-+ /** Pointer to the core interface structure. */
-+ dwc_otg_core_if_t *core_if;
-+
-+ /** Pointer to the PCD structure. */
-+ struct dwc_otg_pcd *pcd;
-+
-+ /** Pointer to the HCD structure. */
-+ struct dwc_otg_hcd *hcd;
-+
-+ /** Flag to indicate whether the common IRQ handler is installed. */
-+ uint8_t common_irq_installed;
-+
-+} dwc_otg_device_t;
-+
-+/*We must clear S3C24XX_EINTPEND external interrupt register
-+ * because after clearing in this register trigerred IRQ from
-+ * H/W core in kernel interrupt can be occured again before OTG
-+ * handlers clear all IRQ sources of Core registers because of
-+ * timing latencies and Low Level IRQ Type.
-+ */
-+#ifdef CONFIG_MACH_IPMATE
-+#define S3C2410X_CLEAR_EINTPEND() \
-+do { \
-+ __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
-+} while (0)
-+#else
-+#define S3C2410X_CLEAR_EINTPEND() do { } while (0)
-+#endif
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,3674 @@
-+
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
-+ * $Revision: #104 $
-+ * $Date: 2011/10/24 $
-+ * $Change: 1871159 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+
-+/** @file
-+ * This file implements HCD Core. All code in this file is portable and doesn't
-+ * use any OS specific functions.
-+ * Interface provided by HCD Core is defined in <code><hcd_if.h></code>
-+ * header file.
-+ */
-+
-+#include <linux/usb.h>
-+#include <linux/usb/hcd.h>
-+
-+#include "dwc_otg_hcd.h"
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_mphi_fix.h"
-+
-+extern bool microframe_schedule, nak_holdoff_enable;
-+
-+//#define DEBUG_HOST_CHANNELS
-+#ifdef DEBUG_HOST_CHANNELS
-+static int last_sel_trans_num_per_scheduled = 0;
-+static int last_sel_trans_num_nonper_scheduled = 0;
-+static int last_sel_trans_num_avail_hc_at_start = 0;
-+static int last_sel_trans_num_avail_hc_at_end = 0;
-+#endif /* DEBUG_HOST_CHANNELS */
-+
-+extern int g_next_sched_frame, g_np_count, g_np_sent;
-+
-+extern haint_data_t haint_saved;
-+extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS];
-+extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS];
-+extern gintsts_data_t ginsts_saved;
-+
-+dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
-+{
-+ return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
-+}
-+
-+/**
-+ * Connection timeout function. An OTG host is required to display a
-+ * message if the device does not connect within 10 seconds.
-+ */
-+void dwc_otg_hcd_connect_timeout(void *ptr)
-+{
-+ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
-+ DWC_PRINTF("Connect Timeout\n");
-+ __DWC_ERROR("Device Not Connected/Responding\n");
-+}
-+
-+#if defined(DEBUG)
-+static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ if (qh->channel != NULL) {
-+ dwc_hc_t *hc = qh->channel;
-+ dwc_list_link_t *item;
-+ dwc_otg_qh_t *qh_item;
-+ int num_channels = hcd->core_if->core_params->host_channels;
-+ int i;
-+
-+ dwc_otg_hc_regs_t *hc_regs;
-+ hcchar_data_t hcchar;
-+ hcsplt_data_t hcsplt;
-+ hctsiz_data_t hctsiz;
-+ uint32_t hcdma;
-+
-+ hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+ hcdma = DWC_READ_REG32(&hc_regs->hcdma);
-+
-+ DWC_PRINTF(" Assigned to channel %p:\n", hc);
-+ DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
-+ hcsplt.d32);
-+ DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
-+ hcdma);
-+ DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
-+ hc->dev_addr, hc->ep_num, hc->ep_is_in);
-+ DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
-+ DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
-+ DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
-+ DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
-+ DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
-+ DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
-+ DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
-+ DWC_PRINTF(" qh: %p\n", hc->qh);
-+ DWC_PRINTF(" NP inactive sched:\n");
-+ DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
-+ qh_item =
-+ DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
-+ DWC_PRINTF(" %p\n", qh_item);
-+ }
-+ DWC_PRINTF(" NP active sched:\n");
-+ DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
-+ qh_item =
-+ DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
-+ DWC_PRINTF(" %p\n", qh_item);
-+ }
-+ DWC_PRINTF(" Channels: \n");
-+ for (i = 0; i < num_channels; i++) {
-+ dwc_hc_t *hc = hcd->hc_ptr_array[i];
-+ DWC_PRINTF(" %2d: %p\n", i, hc);
-+ }
-+ }
-+}
-+#else
-+#define dump_channel_info(hcd, qh)
-+#endif /* DEBUG */
-+
-+/**
-+ * Work queue function for starting the HCD when A-Cable is connected.
-+ * The hcd_start() must be called in a process context.
-+ */
-+static void hcd_start_func(void *_vp)
-+{
-+ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
-+ if (hcd) {
-+ hcd->fops->start(hcd);
-+ }
-+}
-+
-+static void del_xfer_timers(dwc_otg_hcd_t * hcd)
-+{
-+#ifdef DEBUG
-+ int i;
-+ int num_channels = hcd->core_if->core_params->host_channels;
-+ for (i = 0; i < num_channels; i++) {
-+ DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
-+ }
-+#endif
-+}
-+
-+static void del_timers(dwc_otg_hcd_t * hcd)
-+{
-+ del_xfer_timers(hcd);
-+ DWC_TIMER_CANCEL(hcd->conn_timer);
-+}
-+
-+/**
-+ * Processes all the URBs in a single list of QHs. Completes them with
-+ * -ESHUTDOWN and frees the QTD.
-+ */
-+static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
-+{
-+ dwc_list_link_t *qh_item, *qh_tmp;
-+ dwc_otg_qh_t *qh;
-+ dwc_otg_qtd_t *qtd, *qtd_tmp;
-+
-+ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
-+ qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
-+ &qh->qtd_list, qtd_list_entry) {
-+ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
-+ if (qtd->urb != NULL) {
-+ hcd->fops->complete(hcd, qtd->urb->priv,
-+ qtd->urb, -DWC_E_SHUTDOWN);
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
-+ }
-+
-+ }
-+ if(qh->channel) {
-+ /* Using hcchar.chen == 1 is not a reliable test.
-+ * It is possible that the channel has already halted
-+ * but not yet been through the IRQ handler.
-+ */
-+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
-+ DWC_OTG_HC_XFER_URB_DEQUEUE);
-+ if(microframe_schedule)
-+ hcd->available_host_channels++;
-+ qh->channel = NULL;
-+ }
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+ }
-+}
-+
-+/**
-+ * Responds with an error status of ESHUTDOWN to all URBs in the non-periodic
-+ * and periodic schedules. The QTD associated with each URB is removed from
-+ * the schedule and freed. This function may be called when a disconnect is
-+ * detected or when the HCD is being stopped.
-+ */
-+static void kill_all_urbs(dwc_otg_hcd_t * hcd)
-+{
-+ kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
-+ kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
-+ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
-+ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
-+ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
-+ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
-+}
-+
-+/**
-+ * Start the connection timer. An OTG host is required to display a
-+ * message if the device does not connect within 10 seconds. The
-+ * timer is deleted if a port connect interrupt occurs before the
-+ * timer expires.
-+ */
-+static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
-+{
-+ DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
-+}
-+
-+/**
-+ * HCD Callback function for disconnect of the HCD.
-+ *
-+ * @param p void pointer to the <code>struct usb_hcd</code>
-+ */
-+static int32_t dwc_otg_hcd_session_start_cb(void *p)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd;
-+ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
-+ dwc_otg_hcd = p;
-+ dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
-+ return 1;
-+}
-+
-+/**
-+ * HCD Callback function for starting the HCD when A-Cable is
-+ * connected.
-+ *
-+ * @param p void pointer to the <code>struct usb_hcd</code>
-+ */
-+static int32_t dwc_otg_hcd_start_cb(void *p)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = p;
-+ dwc_otg_core_if_t *core_if;
-+ hprt0_data_t hprt0;
-+
-+ core_if = dwc_otg_hcd->core_if;
-+
-+ if (core_if->op_state == B_HOST) {
-+ /*
-+ * Reset the port. During a HNP mode switch the reset
-+ * needs to occur within 1ms and have a duration of at
-+ * least 50ms.
-+ */
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtrst = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ }
-+ DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
-+ hcd_start_func, dwc_otg_hcd, 50,
-+ "start hcd");
-+
-+ return 1;
-+}
-+
-+/**
-+ * HCD Callback function for disconnect of the HCD.
-+ *
-+ * @param p void pointer to the <code>struct usb_hcd</code>
-+ */
-+static int32_t dwc_otg_hcd_disconnect_cb(void *p)
-+{
-+ gintsts_data_t intr;
-+ dwc_otg_hcd_t *dwc_otg_hcd = p;
-+
-+ /*
-+ * Set status flags for the hub driver.
-+ */
-+ dwc_otg_hcd->flags.b.port_connect_status_change = 1;
-+ dwc_otg_hcd->flags.b.port_connect_status = 0;
-+ if(fiq_fix_enable)
-+ local_fiq_disable();
-+ /*
-+ * Shutdown any transfers in process by clearing the Tx FIFO Empty
-+ * interrupt mask and status bits and disabling subsequent host
-+ * channel interrupts.
-+ */
-+ intr.d32 = 0;
-+ intr.b.nptxfempty = 1;
-+ intr.b.ptxfempty = 1;
-+ intr.b.hcintr = 1;
-+ DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
-+ intr.d32, 0);
-+ DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
-+ intr.d32, 0);
-+
-+ del_timers(dwc_otg_hcd);
-+
-+ /*
-+ * Turn off the vbus power only if the core has transitioned to device
-+ * mode. If still in host mode, need to keep power on to detect a
-+ * reconnection.
-+ */
-+ if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
-+ if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+ DWC_PRINTF("Disconnect: PortPower off\n");
-+ hprt0.b.prtpwr = 0;
-+ DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
-+ hprt0.d32);
-+ }
-+
-+ dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
-+ }
-+
-+ /* Respond with an error status to all URBs in the schedule. */
-+ kill_all_urbs(dwc_otg_hcd);
-+
-+ if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
-+ /* Clean up any host channels that were in use. */
-+ int num_channels;
-+ int i;
-+ dwc_hc_t *channel;
-+ dwc_otg_hc_regs_t *hc_regs;
-+ hcchar_data_t hcchar;
-+
-+ num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
-+
-+ if (!dwc_otg_hcd->core_if->dma_enable) {
-+ /* Flush out any channel requests in slave mode. */
-+ for (i = 0; i < num_channels; i++) {
-+ channel = dwc_otg_hcd->hc_ptr_array[i];
-+ if (DWC_CIRCLEQ_EMPTY_ENTRY
-+ (channel, hc_list_entry)) {
-+ hc_regs =
-+ dwc_otg_hcd->core_if->
-+ host_if->hc_regs[i];
-+ hcchar.d32 =
-+ DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chen) {
-+ hcchar.b.chen = 0;
-+ hcchar.b.chdis = 1;
-+ hcchar.b.epdir = 0;
-+ DWC_WRITE_REG32
-+ (&hc_regs->hcchar,
-+ hcchar.d32);
-+ }
-+ }
-+ }
-+ }
-+
-+ for (i = 0; i < num_channels; i++) {
-+ channel = dwc_otg_hcd->hc_ptr_array[i];
-+ if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
-+ hc_regs =
-+ dwc_otg_hcd->core_if->host_if->hc_regs[i];
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chen) {
-+ /* Halt the channel. */
-+ hcchar.b.chdis = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar,
-+ hcchar.d32);
-+ }
-+
-+ dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
-+ channel);
-+ DWC_CIRCLEQ_INSERT_TAIL
-+ (&dwc_otg_hcd->free_hc_list, channel,
-+ hc_list_entry);
-+ /*
-+ * Added for Descriptor DMA to prevent channel double cleanup
-+ * in release_channel_ddma(). Which called from ep_disable
-+ * when device disconnect.
-+ */
-+ channel->qh = NULL;
-+ }
-+ }
-+ if(fiq_split_enable) {
-+ for(i=0; i < 128; i++) {
-+ dwc_otg_hcd->hub_port[i] = 0;
-+ }
-+ haint_saved.d32 = 0;
-+ for(i=0; i < MAX_EPS_CHANNELS; i++) {
-+ hcint_saved[i].d32 = 0;
-+ hcintmsk_saved[i].d32 = 0;
-+ }
-+ }
-+
-+ }
-+
-+ if(fiq_fix_enable)
-+ local_fiq_enable();
-+
-+ if (dwc_otg_hcd->fops->disconnect) {
-+ dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * HCD Callback function for stopping the HCD.
-+ *
-+ * @param p void pointer to the <code>struct usb_hcd</code>
-+ */
-+static int32_t dwc_otg_hcd_stop_cb(void *p)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = p;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
-+ dwc_otg_hcd_stop(dwc_otg_hcd);
-+ return 1;
-+}
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+/**
-+ * HCD Callback function for sleep of HCD.
-+ *
-+ * @param p void pointer to the <code>struct usb_hcd</code>
-+ */
-+static int dwc_otg_hcd_sleep_cb(void *p)
-+{
-+ dwc_otg_hcd_t *hcd = p;
-+
-+ dwc_otg_hcd_free_hc_from_lpm(hcd);
-+
-+ return 0;
-+}
-+#endif
-+
-+
-+/**
-+ * HCD Callback function for Remote Wakeup.
-+ *
-+ * @param p void pointer to the <code>struct usb_hcd</code>
-+ */
-+static int dwc_otg_hcd_rem_wakeup_cb(void *p)
-+{
-+ dwc_otg_hcd_t *hcd = p;
-+
-+ if (hcd->core_if->lx_state == DWC_OTG_L2) {
-+ hcd->flags.b.port_suspend_change = 1;
-+ }
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ else {
-+ hcd->flags.b.port_l1_change = 1;
-+ }
-+#endif
-+ return 0;
-+}
-+
-+/**
-+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
-+ * stopped.
-+ */
-+void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
-+{
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
-+
-+ /*
-+ * The root hub should be disconnected before this function is called.
-+ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
-+ * and the QH lists (via ..._hcd_endpoint_disable).
-+ */
-+
-+ /* Turn off all host-specific interrupts. */
-+ dwc_otg_disable_host_interrupts(hcd->core_if);
-+
-+ /* Turn off the vbus power */
-+ DWC_PRINTF("PortPower off\n");
-+ hprt0.b.prtpwr = 0;
-+ DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
-+ dwc_mdelay(1);
-+}
-+
-+int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
-+ dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
-+ int atomic_alloc)
-+{
-+ int retval = 0;
-+ uint8_t needs_scheduling = 0;
-+ dwc_otg_transaction_type_e tr_type;
-+ dwc_otg_qtd_t *qtd;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+#ifdef DEBUG /* integrity checks (Broadcom) */
-+ if (NULL == hcd->core_if) {
-+ DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n");
-+ /* No longer connected. */
-+ return -DWC_E_INVALID;
-+ }
-+#endif
-+ if (!hcd->flags.b.port_connect_status) {
-+ /* No longer connected. */
-+ DWC_ERROR("Not connected\n");
-+ return -DWC_E_NO_DEVICE;
-+ }
-+
-+ qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
-+ if (qtd == NULL) {
-+ DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+#ifdef DEBUG /* integrity checks (Broadcom) */
-+ if (qtd->urb == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ if (qtd->urb->priv == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+#endif
-+ intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
-+ if(!intr_mask.b.sofintr) needs_scheduling = 1;
-+ if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
-+ /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
-+ needs_scheduling = 0;
-+
-+ retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
-+ // creates a new queue in ep_handle if it doesn't exist already
-+ if (retval < 0) {
-+ DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
-+ "Error status %d\n", retval);
-+ dwc_otg_hcd_qtd_free(qtd);
-+ return retval;
-+ }
-+
-+ if(needs_scheduling) {
-+ tr_type = dwc_otg_hcd_select_transactions(hcd);
-+ if (tr_type != DWC_OTG_TRANSACTION_NONE) {
-+ dwc_otg_hcd_queue_transactions(hcd, tr_type);
-+ }
-+ }
-+ return retval;
-+}
-+
-+int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
-+ dwc_otg_hcd_urb_t * dwc_otg_urb)
-+{
-+ dwc_otg_qh_t *qh;
-+ dwc_otg_qtd_t *urb_qtd;
-+ BUG_ON(!hcd);
-+ BUG_ON(!dwc_otg_urb);
-+
-+#ifdef DEBUG /* integrity checks (Broadcom) */
-+
-+ if (hcd == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n");
-+ return -DWC_E_INVALID;
-+ }
-+ if (dwc_otg_urb == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n");
-+ return -DWC_E_INVALID;
-+ }
-+ if (dwc_otg_urb->qtd == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n");
-+ return -DWC_E_INVALID;
-+ }
-+ urb_qtd = dwc_otg_urb->qtd;
-+ BUG_ON(!urb_qtd);
-+ if (urb_qtd->qh == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
-+ return -DWC_E_INVALID;
-+ }
-+#else
-+ urb_qtd = dwc_otg_urb->qtd;
-+ BUG_ON(!urb_qtd);
-+#endif
-+ qh = urb_qtd->qh;
-+ BUG_ON(!qh);
-+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
-+ if (urb_qtd->in_process) {
-+ dump_channel_info(hcd, qh);
-+ }
-+ }
-+#ifdef DEBUG /* integrity checks (Broadcom) */
-+ if (hcd->core_if == NULL) {
-+ DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n");
-+ return -DWC_E_INVALID;
-+ }
-+#endif
-+ if (urb_qtd->in_process && qh->channel) {
-+ /* The QTD is in process (it has been assigned to a channel). */
-+ if (hcd->flags.b.port_connect_status) {
-+ /*
-+ * If still connected (i.e. in host mode), halt the
-+ * channel so it can be used for other transfers. If
-+ * no longer connected, the host registers can't be
-+ * written to halt the channel since the core is in
-+ * device mode.
-+ */
-+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
-+ DWC_OTG_HC_XFER_URB_DEQUEUE);
-+
-+ dwc_otg_hcd_release_port(hcd, qh);
-+ }
-+ }
-+
-+ /*
-+ * Free the QTD and clean up the associated QH. Leave the QH in the
-+ * schedule if it has any remaining QTDs.
-+ */
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - "
-+ "delete %sQueue handler\n",
-+ hcd->core_if->dma_desc_enable?"DMA ":"");
-+ if (!hcd->core_if->dma_desc_enable) {
-+ uint8_t b = urb_qtd->in_process;
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
-+ if (b) {
-+ dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
-+ qh->channel = NULL;
-+ } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+ }
-+ } else {
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
-+ }
-+ return 0;
-+}
-+
-+int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
-+ int retry)
-+{
-+ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
-+ int retval = 0;
-+ dwc_irqflags_t flags;
-+
-+ if (retry < 0) {
-+ retval = -DWC_E_INVALID;
-+ goto done;
-+ }
-+
-+ if (!qh) {
-+ retval = -DWC_E_INVALID;
-+ goto done;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+
-+ while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ retry--;
-+ dwc_msleep(5);
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ }
-+
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ /*
-+ * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
-+ * and qh_free to prevent stack dump on DWC_DMA_FREE() with
-+ * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
-+ * and dwc_otg_hcd_frame_list_alloc().
-+ */
-+ dwc_otg_hcd_qh_free(hcd, qh);
-+
-+done:
-+ return retval;
-+}
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
-+int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
-+{
-+ int retval = 0;
-+ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
-+ if (!qh)
-+ return -DWC_E_INVALID;
-+
-+ qh->data_toggle = DWC_OTG_HC_PID_DATA0;
-+ return retval;
-+}
-+#endif
-+
-+/**
-+ * HCD Callback structure for handling mode switching.
-+ */
-+static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
-+ .start = dwc_otg_hcd_start_cb,
-+ .stop = dwc_otg_hcd_stop_cb,
-+ .disconnect = dwc_otg_hcd_disconnect_cb,
-+ .session_start = dwc_otg_hcd_session_start_cb,
-+ .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ .sleep = dwc_otg_hcd_sleep_cb,
-+#endif
-+ .p = 0,
-+};
-+
-+/**
-+ * Reset tasklet function
-+ */
-+static void reset_tasklet_func(void *data)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
-+ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
-+ hprt0_data_t hprt0;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
-+
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtrst = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ dwc_mdelay(60);
-+
-+ hprt0.b.prtrst = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ dwc_otg_hcd->flags.b.port_reset_change = 1;
-+}
-+
-+static void completion_tasklet_func(void *ptr)
-+{
-+ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr;
-+ struct urb *urb;
-+ urb_tq_entry_t *item;
-+ dwc_irqflags_t flags;
-+
-+ /* This could just be spin_lock_irq */
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
-+ item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
-+ urb = item->urb;
-+ DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item,
-+ urb_tq_entries);
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ DWC_FREE(item);
-+
-+ usb_hcd_giveback_urb(hcd->priv, urb, urb->status);
-+
-+ fiq_print(FIQDBG_PORTHUB, "COMPLETE");
-+
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ }
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ return;
-+}
-+
-+static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
-+{
-+ dwc_list_link_t *item;
-+ dwc_otg_qh_t *qh;
-+ dwc_irqflags_t flags;
-+
-+ if (!qh_list->next) {
-+ /* The list hasn't been initialized yet. */
-+ return;
-+ }
-+ /*
-+ * Hold spinlock here. Not needed in that case if bellow
-+ * function is being called from ISR
-+ */
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ /* Ensure there are no QTDs or URBs left. */
-+ kill_urbs_in_qh_list(hcd, qh_list);
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+
-+ DWC_LIST_FOREACH(item, qh_list) {
-+ qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
-+ dwc_otg_hcd_qh_remove_and_free(hcd, qh);
-+ }
-+}
-+
-+/**
-+ * Exit from Hibernation if Host did not detect SRP from connected SRP capable
-+ * Device during SRP time by host power up.
-+ */
-+void dwc_otg_hcd_power_up(void *ptr)
-+{
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
-+
-+ DWC_PRINTF("%s called\n", __FUNCTION__);
-+
-+ if (!core_if->hibernation_suspend) {
-+ DWC_PRINTF("Already exited from Hibernation\n");
-+ return;
-+ }
-+
-+ /* Switch on the voltage to the core */
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Reset the core */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Disable power clamps */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ /* Remove reset the core signal */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnrstn = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Disable PMU interrupt */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ core_if->hibernation_suspend = 0;
-+
-+ /* Disable PMU */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+ dwc_udelay(10);
-+
-+ /* Enable VBUS */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.dis_vbus = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
-+
-+ core_if->op_state = A_HOST;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_hcd_start(core_if);
-+}
-+
-+/**
-+ * Frees secondary storage associated with the dwc_otg_hcd structure contained
-+ * in the struct usb_hcd field.
-+ */
-+static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ int i;
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
-+
-+ del_timers(dwc_otg_hcd);
-+
-+ /* Free memory for QH/QTD lists */
-+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
-+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
-+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
-+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
-+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
-+ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
-+
-+ /* Free memory for the host channels. */
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
-+
-+#ifdef DEBUG
-+ if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
-+ DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
-+ }
-+#endif
-+ if (hc != NULL) {
-+ DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
-+ i, hc);
-+ DWC_FREE(hc);
-+ }
-+ }
-+
-+ if (dwc_otg_hcd->core_if->dma_enable) {
-+ if (dwc_otg_hcd->status_buf_dma) {
-+ DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
-+ dwc_otg_hcd->status_buf,
-+ dwc_otg_hcd->status_buf_dma);
-+ }
-+ } else if (dwc_otg_hcd->status_buf != NULL) {
-+ DWC_FREE(dwc_otg_hcd->status_buf);
-+ }
-+ DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock);
-+ DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
-+ /* Set core_if's lock pointer to NULL */
-+ dwc_otg_hcd->core_if->lock = NULL;
-+
-+ DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
-+ DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
-+ DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);
-+
-+#ifdef DWC_DEV_SRPCAP
-+ if (dwc_otg_hcd->core_if->power_down == 2 &&
-+ dwc_otg_hcd->core_if->pwron_timer) {
-+ DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
-+ }
-+#endif
-+ DWC_FREE(dwc_otg_hcd);
-+}
-+
-+int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
-+
-+int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
-+{
-+ int retval = 0;
-+ int num_channels;
-+ int i;
-+ dwc_hc_t *channel;
-+
-+ hcd->lock = DWC_SPINLOCK_ALLOC();
-+ hcd->channel_lock = DWC_SPINLOCK_ALLOC();
-+ DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n",
-+ hcd, core_if);
-+ if (!hcd->lock) {
-+ DWC_ERROR("Could not allocate lock for pcd");
-+ DWC_FREE(hcd);
-+ retval = -DWC_E_NO_MEMORY;
-+ goto out;
-+ }
-+ hcd->core_if = core_if;
-+
-+ /* Register the HCD CIL Callbacks */
-+ dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
-+ &hcd_cil_callbacks, hcd);
-+
-+ /* Initialize the non-periodic schedule. */
-+ DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
-+ DWC_LIST_INIT(&hcd->non_periodic_sched_active);
-+
-+ /* Initialize the periodic schedule. */
-+ DWC_LIST_INIT(&hcd->periodic_sched_inactive);
-+ DWC_LIST_INIT(&hcd->periodic_sched_ready);
-+ DWC_LIST_INIT(&hcd->periodic_sched_assigned);
-+ DWC_LIST_INIT(&hcd->periodic_sched_queued);
-+ DWC_TAILQ_INIT(&hcd->completed_urb_list);
-+ /*
-+ * Create a host channel descriptor for each host channel implemented
-+ * in the controller. Initialize the channel descriptor array.
-+ */
-+ DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
-+ num_channels = hcd->core_if->core_params->host_channels;
-+ DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
-+ for (i = 0; i < num_channels; i++) {
-+ channel = DWC_ALLOC(sizeof(dwc_hc_t));
-+ if (channel == NULL) {
-+ retval = -DWC_E_NO_MEMORY;
-+ DWC_ERROR("%s: host channel allocation failed\n",
-+ __func__);
-+ dwc_otg_hcd_free(hcd);
-+ goto out;
-+ }
-+ channel->hc_num = i;
-+ hcd->hc_ptr_array[i] = channel;
-+#ifdef DEBUG
-+ hcd->core_if->hc_xfer_timer[i] =
-+ DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
-+ &hcd->core_if->hc_xfer_info[i]);
-+#endif
-+ DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
-+ channel);
-+ }
-+
-+ /* Initialize the Connection timeout timer. */
-+ hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
-+ dwc_otg_hcd_connect_timeout, 0);
-+
-+ printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
-+ if (microframe_schedule)
-+ init_hcd_usecs(hcd);
-+
-+ /* Initialize reset tasklet. */
-+ hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
-+
-+ hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet",
-+ completion_tasklet_func, hcd);
-+#ifdef DWC_DEV_SRPCAP
-+ if (hcd->core_if->power_down == 2) {
-+ /* Initialize Power on timer for Host power up in case hibernation */
-+ hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
-+ dwc_otg_hcd_power_up, core_if);
-+ }
-+#endif
-+
-+ /*
-+ * Allocate space for storing data on status transactions. Normally no
-+ * data is sent, but this space acts as a bit bucket. This must be
-+ * done after usb_add_hcd since that function allocates the DMA buffer
-+ * pool.
-+ */
-+ if (hcd->core_if->dma_enable) {
-+ hcd->status_buf =
-+ DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
-+ &hcd->status_buf_dma);
-+ } else {
-+ hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
-+ }
-+ if (!hcd->status_buf) {
-+ retval = -DWC_E_NO_MEMORY;
-+ DWC_ERROR("%s: status_buf allocation failed\n", __func__);
-+ dwc_otg_hcd_free(hcd);
-+ goto out;
-+ }
-+
-+ hcd->otg_port = 1;
-+ hcd->frame_list = NULL;
-+ hcd->frame_list_dma = 0;
-+ hcd->periodic_qh_count = 0;
-+
-+ DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port));
-+#ifdef FIQ_DEBUG
-+ DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc));
-+#endif
-+
-+out:
-+ return retval;
-+}
-+
-+void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
-+{
-+ /* Turn off all host-specific interrupts. */
-+ dwc_otg_disable_host_interrupts(hcd->core_if);
-+
-+ dwc_otg_hcd_free(hcd);
-+}
-+
-+/**
-+ * Initializes dynamic portions of the DWC_otg HCD state.
-+ */
-+static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
-+{
-+ int num_channels;
-+ int i;
-+ dwc_hc_t *channel;
-+ dwc_hc_t *channel_tmp;
-+
-+ hcd->flags.d32 = 0;
-+
-+ hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
-+ if (!microframe_schedule) {
-+ hcd->non_periodic_channels = 0;
-+ hcd->periodic_channels = 0;
-+ } else {
-+ hcd->available_host_channels = hcd->core_if->core_params->host_channels;
-+ }
-+ /*
-+ * Put all channels in the free channel list and clean up channel
-+ * states.
-+ */
-+ DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
-+ &hcd->free_hc_list, hc_list_entry) {
-+ DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
-+ }
-+
-+ num_channels = hcd->core_if->core_params->host_channels;
-+ for (i = 0; i < num_channels; i++) {
-+ channel = hcd->hc_ptr_array[i];
-+ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
-+ hc_list_entry);
-+ dwc_otg_hc_cleanup(hcd->core_if, channel);
-+ }
-+
-+ /* Initialize the DWC core for host mode operation. */
-+ dwc_otg_core_host_init(hcd->core_if);
-+
-+ /* Set core_if's lock pointer to the hcd->lock */
-+ hcd->core_if->lock = hcd->lock;
-+}
-+
-+/**
-+ * Assigns transactions from a QTD to a free host channel and initializes the
-+ * host channel to perform the transactions. The host channel is removed from
-+ * the free list.
-+ *
-+ * @param hcd The HCD state structure.
-+ * @param qh Transactions from the first QTD for this QH are selected and
-+ * assigned to a free host channel.
-+ */
-+static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ dwc_hc_t *hc;
-+ dwc_otg_qtd_t *qtd;
-+ dwc_otg_hcd_urb_t *urb;
-+ void* ptr = NULL;
-+
-+ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
-+
-+ urb = qtd->urb;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length);
-+
-+ if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info))
-+ urb->actual_length = urb->length;
-+
-+
-+ hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
-+
-+ /* Remove the host channel from the free list. */
-+ DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
-+
-+ qh->channel = hc;
-+
-+ qtd->in_process = 1;
-+
-+ /*
-+ * Use usb_pipedevice to determine device address. This address is
-+ * 0 before the SET_ADDRESS command and the correct address afterward.
-+ */
-+ hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
-+ hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
-+ hc->speed = qh->dev_speed;
-+ hc->max_packet = dwc_max_packet(qh->maxp);
-+
-+ hc->xfer_started = 0;
-+ hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
-+ hc->error_state = (qtd->error_count > 0);
-+ hc->halt_on_queue = 0;
-+ hc->halt_pending = 0;
-+ hc->requests = 0;
-+
-+ /*
-+ * The following values may be modified in the transfer type section
-+ * below. The xfer_len value may be reduced when the transfer is
-+ * started to accommodate the max widths of the XferSize and PktCnt
-+ * fields in the HCTSIZn register.
-+ */
-+
-+ hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
-+ if (hc->ep_is_in) {
-+ hc->do_ping = 0;
-+ } else {
-+ hc->do_ping = qh->ping_state;
-+ }
-+
-+ hc->data_pid_start = qh->data_toggle;
-+ hc->multi_count = 1;
-+
-+ if (hcd->core_if->dma_enable) {
-+ hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
-+
-+ /* For non-dword aligned case */
-+ if (((unsigned long)hc->xfer_buff & 0x3)
-+ && !hcd->core_if->dma_desc_enable) {
-+ ptr = (uint8_t *) urb->buf + urb->actual_length;
-+ }
-+ } else {
-+ hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
-+ }
-+ hc->xfer_len = urb->length - urb->actual_length;
-+ hc->xfer_count = 0;
-+
-+ /*
-+ * Set the split attributes
-+ */
-+ hc->do_split = 0;
-+ if (qh->do_split) {
-+ uint32_t hub_addr, port_addr;
-+ hc->do_split = 1;
-+ hc->xact_pos = qtd->isoc_split_pos;
-+ /* We don't need to do complete splits anymore */
-+ if(fiq_split_enable)
-+ hc->complete_split = qtd->complete_split = 0;
-+ else
-+ hc->complete_split = qtd->complete_split;
-+
-+ hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
-+ hc->hub_addr = (uint8_t) hub_addr;
-+ hc->port_addr = (uint8_t) port_addr;
-+ }
-+
-+ switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
-+ case UE_CONTROL:
-+ hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
-+ switch (qtd->control_phase) {
-+ case DWC_OTG_CONTROL_SETUP:
-+ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
-+ hc->do_ping = 0;
-+ hc->ep_is_in = 0;
-+ hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
-+ if (hcd->core_if->dma_enable) {
-+ hc->xfer_buff = (uint8_t *) urb->setup_dma;
-+ } else {
-+ hc->xfer_buff = (uint8_t *) urb->setup_packet;
-+ }
-+ hc->xfer_len = 8;
-+ ptr = NULL;
-+ break;
-+ case DWC_OTG_CONTROL_DATA:
-+ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
-+ hc->data_pid_start = qtd->data_toggle;
-+ break;
-+ case DWC_OTG_CONTROL_STATUS:
-+ /*
-+ * Direction is opposite of data direction or IN if no
-+ * data.
-+ */
-+ DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
-+ if (urb->length == 0) {
-+ hc->ep_is_in = 1;
-+ } else {
-+ hc->ep_is_in =
-+ dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
-+ }
-+ if (hc->ep_is_in) {
-+ hc->do_ping = 0;
-+ }
-+
-+ hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
-+
-+ hc->xfer_len = 0;
-+ if (hcd->core_if->dma_enable) {
-+ hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
-+ } else {
-+ hc->xfer_buff = (uint8_t *) hcd->status_buf;
-+ }
-+ ptr = NULL;
-+ break;
-+ }
-+ break;
-+ case UE_BULK:
-+ hc->ep_type = DWC_OTG_EP_TYPE_BULK;
-+ break;
-+ case UE_INTERRUPT:
-+ hc->ep_type = DWC_OTG_EP_TYPE_INTR;
-+ break;
-+ case UE_ISOCHRONOUS:
-+ {
-+ struct dwc_otg_hcd_iso_packet_desc *frame_desc;
-+
-+ hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
-+
-+ if (hcd->core_if->dma_desc_enable)
-+ break;
-+
-+ frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
-+
-+ frame_desc->status = 0;
-+
-+ if (hcd->core_if->dma_enable) {
-+ hc->xfer_buff = (uint8_t *) urb->dma;
-+ } else {
-+ hc->xfer_buff = (uint8_t *) urb->buf;
-+ }
-+ hc->xfer_buff +=
-+ frame_desc->offset + qtd->isoc_split_offset;
-+ hc->xfer_len =
-+ frame_desc->length - qtd->isoc_split_offset;
-+
-+ /* For non-dword aligned buffers */
-+ if (((unsigned long)hc->xfer_buff & 0x3)
-+ && hcd->core_if->dma_enable) {
-+ ptr =
-+ (uint8_t *) urb->buf + frame_desc->offset +
-+ qtd->isoc_split_offset;
-+ } else
-+ ptr = NULL;
-+
-+ if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
-+ if (hc->xfer_len <= 188) {
-+ hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
-+ } else {
-+ hc->xact_pos =
-+ DWC_HCSPLIT_XACTPOS_BEGIN;
-+ }
-+ }
-+ }
-+ break;
-+ }
-+ /* non DWORD-aligned buffer case */
-+ if (ptr) {
-+ uint32_t buf_size;
-+ if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
-+ buf_size = hcd->core_if->core_params->max_transfer_size;
-+ } else {
-+ buf_size = 4096;
-+ }
-+ if (!qh->dw_align_buf) {
-+ qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
-+ &qh->dw_align_buf_dma);
-+ if (!qh->dw_align_buf) {
-+ DWC_ERROR
-+ ("%s: Failed to allocate memory to handle "
-+ "non-dword aligned buffer case\n",
-+ __func__);
-+ return;
-+ }
-+ }
-+ if (!hc->ep_is_in) {
-+ dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
-+ }
-+ hc->align_buff = qh->dw_align_buf_dma;
-+ } else {
-+ hc->align_buff = 0;
-+ }
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ /*
-+ * This value may be modified when the transfer is started to
-+ * reflect the actual transfer length.
-+ */
-+ hc->multi_count = dwc_hb_mult(qh->maxp);
-+ }
-+
-+ if (hcd->core_if->dma_desc_enable)
-+ hc->desc_list_addr = qh->desc_list_dma;
-+
-+ dwc_otg_hc_init(hcd->core_if, hc);
-+ hc->qh = qh;
-+}
-+
-+/*
-+** Check the transaction to see if the port / hub has already been assigned for
-+** a split transaction
-+**
-+** Return 0 - Port is already in use
-+*/
-+int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh)
-+{
-+ uint32_t hub_addr, port_addr;
-+
-+ if(!fiq_split_enable)
-+ return 0;
-+
-+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr);
-+
-+ if(hcd->hub_port[hub_addr] & (1 << port_addr))
-+ {
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:S%02d", hub_addr, port_addr, qh->skip_count);
-+
-+ qh->skip_count++;
-+
-+ if(qh->skip_count > 40000)
-+ {
-+ printk_once(KERN_ERR "Error: Having to skip port allocation");
-+ local_fiq_disable();
-+ BUG();
-+ return 0;
-+ }
-+ return 1;
-+ }
-+ else
-+ {
-+ qh->skip_count = 0;
-+ hcd->hub_port[hub_addr] |= 1 << port_addr;
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num);
-+#ifdef FIQ_DEBUG
-+ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd);
-+#endif
-+ return 0;
-+ }
-+}
-+void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh)
-+{
-+ uint32_t hub_addr, port_addr;
-+
-+ if(!fiq_split_enable)
-+ return;
-+
-+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr);
-+
-+ hcd->hub_port[hub_addr] &= ~(1 << port_addr);
-+#ifdef FIQ_DEBUG
-+ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1;
-+#endif
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num);
-+
-+}
-+
-+
-+/**
-+ * This function selects transactions from the HCD transfer schedule and
-+ * assigns them to available host channels. It is called from HCD interrupt
-+ * handler functions.
-+ *
-+ * @param hcd The HCD state structure.
-+ *
-+ * @return The types of new transactions that were assigned to host channels.
-+ */
-+dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
-+{
-+ dwc_list_link_t *qh_ptr;
-+ dwc_otg_qh_t *qh;
-+ dwc_otg_qtd_t *qtd;
-+ int num_channels;
-+ dwc_irqflags_t flags;
-+ dwc_spinlock_t *channel_lock = hcd->channel_lock;
-+ dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
-+
-+#ifdef DEBUG_SOF
-+ DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
-+#endif
-+
-+#ifdef DEBUG_HOST_CHANNELS
-+ last_sel_trans_num_per_scheduled = 0;
-+ last_sel_trans_num_nonper_scheduled = 0;
-+ last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
-+#endif /* DEBUG_HOST_CHANNELS */
-+
-+ /* Process entries in the periodic ready list. */
-+ qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
-+
-+ while (qh_ptr != &hcd->periodic_sched_ready &&
-+ !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
-+
-+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-+
-+ if(qh->do_split) {
-+ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
-+ if(!(qh->ep_type == UE_ISOCHRONOUS &&
-+ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
-+ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) {
-+ if(dwc_otg_hcd_allocate_port(hcd, qh))
-+ {
-+ qh_ptr = DWC_LIST_NEXT(qh_ptr);
-+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1);
-+ continue;
-+ }
-+ }
-+ }
-+
-+ if (microframe_schedule) {
-+ // Make sure we leave one channel for non periodic transactions.
-+ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
-+ if (hcd->available_host_channels <= 1) {
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+ if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh);
-+ break;
-+ }
-+ hcd->available_host_channels--;
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+#ifdef DEBUG_HOST_CHANNELS
-+ last_sel_trans_num_per_scheduled++;
-+#endif /* DEBUG_HOST_CHANNELS */
-+ }
-+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-+ assign_and_init_hc(hcd, qh);
-+
-+ /*
-+ * Move the QH from the periodic ready schedule to the
-+ * periodic assigned schedule.
-+ */
-+ qh_ptr = DWC_LIST_NEXT(qh_ptr);
-+ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
-+ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
-+ &qh->qh_list_entry);
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+ }
-+
-+ /*
-+ * Process entries in the inactive portion of the non-periodic
-+ * schedule. Some free host channels may not be used if they are
-+ * reserved for periodic transfers.
-+ */
-+ qh_ptr = hcd->non_periodic_sched_inactive.next;
-+ num_channels = hcd->core_if->core_params->host_channels;
-+ while (qh_ptr != &hcd->non_periodic_sched_inactive &&
-+ (microframe_schedule || hcd->non_periodic_channels <
-+ num_channels - hcd->periodic_channels) &&
-+ !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
-+
-+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-+
-+ /*
-+ * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
-+ * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed
-+ * cheeky devices that just hold off using NAKs
-+ */
-+ if (nak_holdoff_enable && qh->do_split) {
-+ if (qh->nak_frame != 0xffff &&
-+ dwc_full_frame_num(qh->nak_frame) ==
-+ dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
-+ /*
-+ * Revisit: Need to avoid trampling on periodic scheduling.
-+ * Currently we are safe because g_np_count != g_np_sent whenever we hit this,
-+ * but if this behaviour is changed then periodic endpoints will get a slower
-+ * polling rate.
-+ */
-+ g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
-+ qh_ptr = DWC_LIST_NEXT(qh_ptr);
-+ continue;
-+ } else {
-+ qh->nak_frame = 0xffff;
-+ }
-+ }
-+
-+ if (microframe_schedule) {
-+ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
-+ if (hcd->available_host_channels < 1) {
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+ break;
-+ }
-+ hcd->available_host_channels--;
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+#ifdef DEBUG_HOST_CHANNELS
-+ last_sel_trans_num_nonper_scheduled++;
-+#endif /* DEBUG_HOST_CHANNELS */
-+ }
-+
-+ assign_and_init_hc(hcd, qh);
-+
-+ /*
-+ * Move the QH from the non-periodic inactive schedule to the
-+ * non-periodic active schedule.
-+ */
-+ qh_ptr = DWC_LIST_NEXT(qh_ptr);
-+ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
-+ DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
-+ &qh->qh_list_entry);
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+
-+ g_np_sent++;
-+
-+ if (!microframe_schedule)
-+ hcd->non_periodic_channels++;
-+ }
-+
-+ if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned))
-+ ret_val |= DWC_OTG_TRANSACTION_PERIODIC;
-+
-+ if(!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active))
-+ ret_val |= DWC_OTG_TRANSACTION_NON_PERIODIC;
-+
-+
-+#ifdef DEBUG_HOST_CHANNELS
-+ last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
-+#endif /* DEBUG_HOST_CHANNELS */
-+ return ret_val;
-+}
-+
-+/**
-+ * Attempts to queue a single transaction request for a host channel
-+ * associated with either a periodic or non-periodic transfer. This function
-+ * assumes that there is space available in the appropriate request queue. For
-+ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
-+ * is available in the appropriate Tx FIFO.
-+ *
-+ * @param hcd The HCD state structure.
-+ * @param hc Host channel descriptor associated with either a periodic or
-+ * non-periodic transfer.
-+ * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx
-+ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
-+ * transfers.
-+ *
-+ * @return 1 if a request is queued and more requests may be needed to
-+ * complete the transfer, 0 if no more requests are required for this
-+ * transfer, -1 if there is insufficient space in the Tx FIFO.
-+ */
-+static int queue_transaction(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc, uint16_t fifo_dwords_avail)
-+{
-+ int retval;
-+
-+ if (hcd->core_if->dma_enable) {
-+ if (hcd->core_if->dma_desc_enable) {
-+ if (!hc->xfer_started
-+ || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
-+ dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
-+ hc->qh->ping_state = 0;
-+ }
-+ } else if (!hc->xfer_started) {
-+ dwc_otg_hc_start_transfer(hcd->core_if, hc);
-+ hc->qh->ping_state = 0;
-+ }
-+ retval = 0;
-+ } else if (hc->halt_pending) {
-+ /* Don't queue a request if the channel has been halted. */
-+ retval = 0;
-+ } else if (hc->halt_on_queue) {
-+ dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
-+ retval = 0;
-+ } else if (hc->do_ping) {
-+ if (!hc->xfer_started) {
-+ dwc_otg_hc_start_transfer(hcd->core_if, hc);
-+ }
-+ retval = 0;
-+ } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
-+ if ((fifo_dwords_avail * 4) >= hc->max_packet) {
-+ if (!hc->xfer_started) {
-+ dwc_otg_hc_start_transfer(hcd->core_if, hc);
-+ retval = 1;
-+ } else {
-+ retval =
-+ dwc_otg_hc_continue_transfer(hcd->core_if,
-+ hc);
-+ }
-+ } else {
-+ retval = -1;
-+ }
-+ } else {
-+ if (!hc->xfer_started) {
-+ dwc_otg_hc_start_transfer(hcd->core_if, hc);
-+ retval = 1;
-+ } else {
-+ retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
-+ }
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * Processes periodic channels for the next frame and queues transactions for
-+ * these channels to the DWC_otg controller. After queueing transactions, the
-+ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
-+ * to queue as Periodic Tx FIFO or request queue space becomes available.
-+ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
-+ */
-+static void process_periodic_channels(dwc_otg_hcd_t * hcd)
-+{
-+ hptxsts_data_t tx_status;
-+ dwc_list_link_t *qh_ptr;
-+ dwc_otg_qh_t *qh;
-+ int status;
-+ int no_queue_space = 0;
-+ int no_fifo_space = 0;
-+
-+ dwc_otg_host_global_regs_t *host_regs;
-+ host_regs = hcd->core_if->host_if->host_global_regs;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
-+#ifdef DEBUG
-+ tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " P Tx Req Queue Space Avail (before queue): %d\n",
-+ tx_status.b.ptxqspcavail);
-+ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
-+ tx_status.b.ptxfspcavail);
-+#endif
-+
-+ qh_ptr = hcd->periodic_sched_assigned.next;
-+ while (qh_ptr != &hcd->periodic_sched_assigned) {
-+ tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
-+ if (tx_status.b.ptxqspcavail == 0) {
-+ no_queue_space = 1;
-+ break;
-+ }
-+
-+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-+
-+ // Do not send a split start transaction any later than frame .6
-+ // Note, we have to schedule a periodic in .5 to make it go in .6
-+ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6)
-+ {
-+ qh_ptr = qh_ptr->next;
-+ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7;
-+ continue;
-+ }
-+
-+ /*
-+ * Set a flag if we're queuing high-bandwidth in slave mode.
-+ * The flag prevents any halts to get into the request queue in
-+ * the middle of multiple high-bandwidth packets getting queued.
-+ */
-+ if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
-+ hcd->core_if->queuing_high_bandwidth = 1;
-+ }
-+ status =
-+ queue_transaction(hcd, qh->channel,
-+ tx_status.b.ptxfspcavail);
-+ if (status < 0) {
-+ no_fifo_space = 1;
-+ break;
-+ }
-+
-+ /*
-+ * In Slave mode, stay on the current transfer until there is
-+ * nothing more to do or the high-bandwidth request count is
-+ * reached. In DMA mode, only need to queue one request. The
-+ * controller automatically handles multiple packets for
-+ * high-bandwidth transfers.
-+ */
-+ if (hcd->core_if->dma_enable || status == 0 ||
-+ qh->channel->requests == qh->channel->multi_count) {
-+ qh_ptr = qh_ptr->next;
-+ /*
-+ * Move the QH from the periodic assigned schedule to
-+ * the periodic queued schedule.
-+ */
-+ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
-+ &qh->qh_list_entry);
-+
-+ /* done queuing high bandwidth */
-+ hcd->core_if->queuing_high_bandwidth = 0;
-+ }
-+ }
-+
-+ if (!hcd->core_if->dma_enable) {
-+ dwc_otg_core_global_regs_t *global_regs;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ global_regs = hcd->core_if->core_global_regs;
-+ intr_mask.b.ptxfempty = 1;
-+#ifdef DEBUG
-+ tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " P Tx Req Queue Space Avail (after queue): %d\n",
-+ tx_status.b.ptxqspcavail);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " P Tx FIFO Space Avail (after queue): %d\n",
-+ tx_status.b.ptxfspcavail);
-+#endif
-+ if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
-+ no_queue_space || no_fifo_space) {
-+ /*
-+ * May need to queue more transactions as the request
-+ * queue or Tx FIFO empties. Enable the periodic Tx
-+ * FIFO empty interrupt. (Always use the half-empty
-+ * level to ensure that new requests are loaded as
-+ * soon as possible.)
-+ */
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
-+ intr_mask.d32);
-+ } else {
-+ /*
-+ * Disable the Tx FIFO empty interrupt since there are
-+ * no more transactions that need to be queued right
-+ * now. This function is called from interrupt
-+ * handlers to queue more transactions as transfer
-+ * states change.
-+ */
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
-+ 0);
-+ }
-+ }
-+}
-+
-+/**
-+ * Processes active non-periodic channels and queues transactions for these
-+ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
-+ * FIFO Empty interrupt is enabled if there are more transactions to queue as
-+ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
-+ * FIFO Empty interrupt is disabled.
-+ */
-+static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
-+{
-+ gnptxsts_data_t tx_status;
-+ dwc_list_link_t *orig_qh_ptr;
-+ dwc_otg_qh_t *qh;
-+ int status;
-+ int no_queue_space = 0;
-+ int no_fifo_space = 0;
-+ int more_to_do = 0;
-+
-+ dwc_otg_core_global_regs_t *global_regs =
-+ hcd->core_if->core_global_regs;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
-+#ifdef DEBUG
-+ tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " NP Tx Req Queue Space Avail (before queue): %d\n",
-+ tx_status.b.nptxqspcavail);
-+ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
-+ tx_status.b.nptxfspcavail);
-+#endif
-+ /*
-+ * Keep track of the starting point. Skip over the start-of-list
-+ * entry.
-+ */
-+ if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
-+ hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
-+ }
-+ orig_qh_ptr = hcd->non_periodic_qh_ptr;
-+
-+ /*
-+ * Process once through the active list or until no more space is
-+ * available in the request queue or the Tx FIFO.
-+ */
-+ do {
-+ tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
-+ if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
-+ no_queue_space = 1;
-+ break;
-+ }
-+
-+ qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
-+ qh_list_entry);
-+
-+ // Do not send a split start transaction any later than frame .5
-+ // non periodic transactions will start immediately in this uframe
-+ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6)
-+ {
-+ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7;
-+ break;
-+ }
-+
-+ status =
-+ queue_transaction(hcd, qh->channel,
-+ tx_status.b.nptxfspcavail);
-+
-+ if (status > 0) {
-+ more_to_do = 1;
-+ } else if (status < 0) {
-+ no_fifo_space = 1;
-+ break;
-+ }
-+
-+ /* Advance to next QH, skipping start-of-list entry. */
-+ hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
-+ if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
-+ hcd->non_periodic_qh_ptr =
-+ hcd->non_periodic_qh_ptr->next;
-+ }
-+
-+ } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
-+
-+ if (!hcd->core_if->dma_enable) {
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ intr_mask.b.nptxfempty = 1;
-+
-+#ifdef DEBUG
-+ tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " NP Tx Req Queue Space Avail (after queue): %d\n",
-+ tx_status.b.nptxqspcavail);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " NP Tx FIFO Space Avail (after queue): %d\n",
-+ tx_status.b.nptxfspcavail);
-+#endif
-+ if (more_to_do || no_queue_space || no_fifo_space) {
-+ /*
-+ * May need to queue more transactions as the request
-+ * queue or Tx FIFO empties. Enable the non-periodic
-+ * Tx FIFO empty interrupt. (Always use the half-empty
-+ * level to ensure that new requests are loaded as
-+ * soon as possible.)
-+ */
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
-+ intr_mask.d32);
-+ } else {
-+ /*
-+ * Disable the Tx FIFO empty interrupt since there are
-+ * no more transactions that need to be queued right
-+ * now. This function is called from interrupt
-+ * handlers to queue more transactions as transfer
-+ * states change.
-+ */
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
-+ 0);
-+ }
-+ }
-+}
-+
-+/**
-+ * This function processes the currently active host channels and queues
-+ * transactions for these channels to the DWC_otg controller. It is called
-+ * from HCD interrupt handler functions.
-+ *
-+ * @param hcd The HCD state structure.
-+ * @param tr_type The type(s) of transactions to queue (non-periodic,
-+ * periodic, or both).
-+ */
-+void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
-+ dwc_otg_transaction_type_e tr_type)
-+{
-+#ifdef DEBUG_SOF
-+ DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
-+#endif
-+ /* Process host channels associated with periodic transfers. */
-+ if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
-+ tr_type == DWC_OTG_TRANSACTION_ALL) &&
-+ !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
-+
-+ process_periodic_channels(hcd);
-+ }
-+
-+ /* Process host channels associated with non-periodic transfers. */
-+ if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
-+ tr_type == DWC_OTG_TRANSACTION_ALL) {
-+ if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
-+ process_non_periodic_channels(hcd);
-+ } else {
-+ /*
-+ * Ensure NP Tx FIFO empty interrupt is disabled when
-+ * there are no non-periodic transfers to process.
-+ */
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+ gintmsk.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&hcd->core_if->
-+ core_global_regs->gintmsk, gintmsk.d32,
-+ 0);
-+ }
-+ }
-+}
-+
-+#ifdef DWC_HS_ELECT_TST
-+/*
-+ * Quick and dirty hack to implement the HS Electrical Test
-+ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
-+ *
-+ * This code was copied from our userspace app "hset". It sends a
-+ * Get Device Descriptor control sequence in two parts, first the
-+ * Setup packet by itself, followed some time later by the In and
-+ * Ack packets. Rather than trying to figure out how to add this
-+ * functionality to the normal driver code, we just hijack the
-+ * hardware, using these two function to drive the hardware
-+ * directly.
-+ */
-+
-+static dwc_otg_core_global_regs_t *global_regs;
-+static dwc_otg_host_global_regs_t *hc_global_regs;
-+static dwc_otg_hc_regs_t *hc_regs;
-+static uint32_t *data_fifo;
-+
-+static void do_setup(void)
-+{
-+ gintsts_data_t gintsts;
-+ hctsiz_data_t hctsiz;
-+ hcchar_data_t hcchar;
-+ haint_data_t haint;
-+ hcint_data_t hcint;
-+
-+ /* Enable HAINTs */
-+ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
-+
-+ /* Enable HCINTs */
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /*
-+ * Send Setup packet (Get Device Descriptor)
-+ */
-+
-+ /* Make sure channel is disabled */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chen) {
-+ hcchar.b.chdis = 1;
-+// hcchar.b.chen = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+ //sleep(1);
-+ dwc_mdelay(1000);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ }
-+
-+ /* Set HCTSIZ */
-+ hctsiz.d32 = 0;
-+ hctsiz.b.xfersize = 8;
-+ hctsiz.b.pktcnt = 1;
-+ hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
-+ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
-+
-+ /* Set HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
-+ hcchar.b.epdir = 0;
-+ hcchar.b.epnum = 0;
-+ hcchar.b.mps = 8;
-+ hcchar.b.chen = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+
-+ /* Fill FIFO with Setup data for Get Device Descriptor */
-+ data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
-+ DWC_WRITE_REG32(data_fifo++, 0x01000680);
-+ DWC_WRITE_REG32(data_fifo++, 0x00080000);
-+
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Wait for host channel interrupt */
-+ do {
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+ } while (gintsts.b.hcintr == 0);
-+
-+ /* Disable HCINTs */
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
-+
-+ /* Disable HAINTs */
-+ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+}
-+
-+static void do_in_ack(void)
-+{
-+ gintsts_data_t gintsts;
-+ hctsiz_data_t hctsiz;
-+ hcchar_data_t hcchar;
-+ haint_data_t haint;
-+ hcint_data_t hcint;
-+ host_grxsts_data_t grxsts;
-+
-+ /* Enable HAINTs */
-+ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
-+
-+ /* Enable HCINTs */
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /*
-+ * Receive Control In packet
-+ */
-+
-+ /* Make sure channel is disabled */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chen) {
-+ hcchar.b.chdis = 1;
-+ hcchar.b.chen = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+ //sleep(1);
-+ dwc_mdelay(1000);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ }
-+
-+ /* Set HCTSIZ */
-+ hctsiz.d32 = 0;
-+ hctsiz.b.xfersize = 8;
-+ hctsiz.b.pktcnt = 1;
-+ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
-+ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
-+
-+ /* Set HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
-+ hcchar.b.epdir = 1;
-+ hcchar.b.epnum = 0;
-+ hcchar.b.mps = 8;
-+ hcchar.b.chen = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Wait for receive status queue interrupt */
-+ do {
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+ } while (gintsts.b.rxstsqlvl == 0);
-+
-+ /* Read RXSTS */
-+ grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
-+
-+ /* Clear RXSTSQLVL in GINTSTS */
-+ gintsts.d32 = 0;
-+ gintsts.b.rxstsqlvl = 1;
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ switch (grxsts.b.pktsts) {
-+ case DWC_GRXSTS_PKTSTS_IN:
-+ /* Read the data into the host buffer */
-+ if (grxsts.b.bcnt > 0) {
-+ int i;
-+ int word_count = (grxsts.b.bcnt + 3) / 4;
-+
-+ data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
-+
-+ for (i = 0; i < word_count; i++) {
-+ (void)DWC_READ_REG32(data_fifo++);
-+ }
-+ }
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Wait for receive status queue interrupt */
-+ do {
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+ } while (gintsts.b.rxstsqlvl == 0);
-+
-+ /* Read RXSTS */
-+ grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
-+
-+ /* Clear RXSTSQLVL in GINTSTS */
-+ gintsts.d32 = 0;
-+ gintsts.b.rxstsqlvl = 1;
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ switch (grxsts.b.pktsts) {
-+ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Wait for host channel interrupt */
-+ do {
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+ } while (gintsts.b.hcintr == 0);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+// usleep(100000);
-+// mdelay(100);
-+ dwc_mdelay(1);
-+
-+ /*
-+ * Send handshake packet
-+ */
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Make sure channel is disabled */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chen) {
-+ hcchar.b.chdis = 1;
-+ hcchar.b.chen = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+ //sleep(1);
-+ dwc_mdelay(1000);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ }
-+
-+ /* Set HCTSIZ */
-+ hctsiz.d32 = 0;
-+ hctsiz.b.xfersize = 0;
-+ hctsiz.b.pktcnt = 1;
-+ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
-+ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
-+
-+ /* Set HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
-+ hcchar.b.epdir = 0;
-+ hcchar.b.epnum = 0;
-+ hcchar.b.mps = 8;
-+ hcchar.b.chen = 1;
-+ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
-+
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+
-+ /* Wait for host channel interrupt */
-+ do {
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+ } while (gintsts.b.hcintr == 0);
-+
-+ /* Disable HCINTs */
-+ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
-+
-+ /* Disable HAINTs */
-+ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
-+
-+ /* Read HAINT */
-+ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
-+
-+ /* Read HCINT */
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+
-+ /* Read HCCHAR */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+
-+ /* Clear HCINT */
-+ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
-+
-+ /* Clear HAINT */
-+ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
-+
-+ /* Clear GINTSTS */
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ /* Read GINTSTS */
-+ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
-+}
-+#endif
-+
-+/** Handles hub class-specific requests. */
-+int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
-+ uint16_t typeReq,
-+ uint16_t wValue,
-+ uint16_t wIndex, uint8_t * buf, uint16_t wLength)
-+{
-+ int retval = 0;
-+
-+ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
-+ usb_hub_descriptor_t *hub_desc;
-+ hprt0_data_t hprt0 = {.d32 = 0 };
-+
-+ uint32_t port_status;
-+
-+ switch (typeReq) {
-+ case UCR_CLEAR_HUB_FEATURE:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearHubFeature 0x%x\n", wValue);
-+ switch (wValue) {
-+ case UHF_C_HUB_LOCAL_POWER:
-+ case UHF_C_HUB_OVER_CURRENT:
-+ /* Nothing required here */
-+ break;
-+ default:
-+ retval = -DWC_E_INVALID;
-+ DWC_ERROR("DWC OTG HCD - "
-+ "ClearHubFeature request %xh unknown\n",
-+ wValue);
-+ }
-+ break;
-+ case UCR_CLEAR_PORT_FEATURE:
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ if (wValue != UHF_PORT_L1)
-+#endif
-+ if (!wIndex || wIndex > 1)
-+ goto error;
-+
-+ switch (wValue) {
-+ case UHF_PORT_ENABLE:
-+ DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtena = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ break;
-+ case UHF_PORT_SUSPEND:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
-+
-+ if (core_if->power_down == 2) {
-+ dwc_otg_host_hibernation_restore(core_if, 0, 0);
-+ } else {
-+ DWC_WRITE_REG32(core_if->pcgcctl, 0);
-+ dwc_mdelay(5);
-+
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtres = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ hprt0.b.prtsusp = 0;
-+ /* Clear Resume bit */
-+ dwc_mdelay(100);
-+ hprt0.b.prtres = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ }
-+ break;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ case UHF_PORT_L1:
-+ {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ glpmcfg_data_t lpmcfg = {.d32 = 0 };
-+
-+ lpmcfg.d32 =
-+ DWC_READ_REG32(&core_if->
-+ core_global_regs->glpmcfg);
-+ lpmcfg.b.en_utmi_sleep = 0;
-+ lpmcfg.b.hird_thres &= (~(1 << 4));
-+ lpmcfg.b.prt_sleep_sts = 1;
-+ DWC_WRITE_REG32(&core_if->
-+ core_global_regs->glpmcfg,
-+ lpmcfg.d32);
-+
-+ /* Clear Enbl_L1Gating bit. */
-+ pcgcctl.b.enbl_sleep_gating = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
-+ 0);
-+
-+ dwc_mdelay(5);
-+
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtres = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0,
-+ hprt0.d32);
-+ /* This bit will be cleared in wakeup interrupt handle */
-+ break;
-+ }
-+#endif
-+ case UHF_PORT_POWER:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_POWER\n");
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtpwr = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ break;
-+ case UHF_PORT_INDICATOR:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
-+ /* Port inidicator not supported */
-+ break;
-+ case UHF_C_PORT_CONNECTION:
-+ /* Clears drivers internal connect status change
-+ * flag */
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
-+ dwc_otg_hcd->flags.b.port_connect_status_change = 0;
-+ break;
-+ case UHF_C_PORT_RESET:
-+ /* Clears the driver's internal Port Reset Change
-+ * flag */
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
-+ dwc_otg_hcd->flags.b.port_reset_change = 0;
-+ break;
-+ case UHF_C_PORT_ENABLE:
-+ /* Clears the driver's internal Port
-+ * Enable/Disable Change flag */
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
-+ dwc_otg_hcd->flags.b.port_enable_change = 0;
-+ break;
-+ case UHF_C_PORT_SUSPEND:
-+ /* Clears the driver's internal Port Suspend
-+ * Change flag, which is set when resume signaling on
-+ * the host port is complete */
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
-+ dwc_otg_hcd->flags.b.port_suspend_change = 0;
-+ break;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ case UHF_C_PORT_L1:
-+ dwc_otg_hcd->flags.b.port_l1_change = 0;
-+ break;
-+#endif
-+ case UHF_C_PORT_OVER_CURRENT:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
-+ dwc_otg_hcd->flags.b.port_over_current_change = 0;
-+ break;
-+ default:
-+ retval = -DWC_E_INVALID;
-+ DWC_ERROR("DWC OTG HCD - "
-+ "ClearPortFeature request %xh "
-+ "unknown or unsupported\n", wValue);
-+ }
-+ break;
-+ case UCR_GET_HUB_DESCRIPTOR:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "GetHubDescriptor\n");
-+ hub_desc = (usb_hub_descriptor_t *) buf;
-+ hub_desc->bDescLength = 9;
-+ hub_desc->bDescriptorType = 0x29;
-+ hub_desc->bNbrPorts = 1;
-+ USETW(hub_desc->wHubCharacteristics, 0x08);
-+ hub_desc->bPwrOn2PwrGood = 1;
-+ hub_desc->bHubContrCurrent = 0;
-+ hub_desc->DeviceRemovable[0] = 0;
-+ hub_desc->DeviceRemovable[1] = 0xff;
-+ break;
-+ case UCR_GET_HUB_STATUS:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "GetHubStatus\n");
-+ DWC_MEMSET(buf, 0, 4);
-+ break;
-+ case UCR_GET_PORT_STATUS:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
-+ wIndex, dwc_otg_hcd->flags.d32);
-+ if (!wIndex || wIndex > 1)
-+ goto error;
-+
-+ port_status = 0;
-+
-+ if (dwc_otg_hcd->flags.b.port_connect_status_change)
-+ port_status |= (1 << UHF_C_PORT_CONNECTION);
-+
-+ if (dwc_otg_hcd->flags.b.port_enable_change)
-+ port_status |= (1 << UHF_C_PORT_ENABLE);
-+
-+ if (dwc_otg_hcd->flags.b.port_suspend_change)
-+ port_status |= (1 << UHF_C_PORT_SUSPEND);
-+
-+ if (dwc_otg_hcd->flags.b.port_l1_change)
-+ port_status |= (1 << UHF_C_PORT_L1);
-+
-+ if (dwc_otg_hcd->flags.b.port_reset_change) {
-+ port_status |= (1 << UHF_C_PORT_RESET);
-+ }
-+
-+ if (dwc_otg_hcd->flags.b.port_over_current_change) {
-+ DWC_WARN("Overcurrent change detected\n");
-+ port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
-+ }
-+
-+ if (!dwc_otg_hcd->flags.b.port_connect_status) {
-+ /*
-+ * The port is disconnected, which means the core is
-+ * either in device mode or it soon will be. Just
-+ * return 0's for the remainder of the port status
-+ * since the port register can't be read if the core
-+ * is in device mode.
-+ */
-+ *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
-+ break;
-+ }
-+
-+ hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
-+ DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
-+
-+ if (hprt0.b.prtconnsts)
-+ port_status |= (1 << UHF_PORT_CONNECTION);
-+
-+ if (hprt0.b.prtena)
-+ port_status |= (1 << UHF_PORT_ENABLE);
-+
-+ if (hprt0.b.prtsusp)
-+ port_status |= (1 << UHF_PORT_SUSPEND);
-+
-+ if (hprt0.b.prtovrcurract)
-+ port_status |= (1 << UHF_PORT_OVER_CURRENT);
-+
-+ if (hprt0.b.prtrst)
-+ port_status |= (1 << UHF_PORT_RESET);
-+
-+ if (hprt0.b.prtpwr)
-+ port_status |= (1 << UHF_PORT_POWER);
-+
-+ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
-+ port_status |= (1 << UHF_PORT_HIGH_SPEED);
-+ else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
-+ port_status |= (1 << UHF_PORT_LOW_SPEED);
-+
-+ if (hprt0.b.prttstctl)
-+ port_status |= (1 << UHF_PORT_TEST);
-+ if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
-+ port_status |= (1 << UHF_PORT_L1);
-+ }
-+ /*
-+ For Synopsys HW emulation of Power down wkup_control asserts the
-+ hreset_n and prst_n on suspned. This causes the HPRT0 to be zero.
-+ We intentionally tell the software that port is in L2Suspend state.
-+ Only for STE.
-+ */
-+ if ((core_if->power_down == 2)
-+ && (core_if->hibernation_suspend == 1)) {
-+ port_status |= (1 << UHF_PORT_SUSPEND);
-+ }
-+ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
-+
-+ *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
-+
-+ break;
-+ case UCR_SET_HUB_FEATURE:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "SetHubFeature\n");
-+ /* No HUB features supported */
-+ break;
-+ case UCR_SET_PORT_FEATURE:
-+ if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
-+ goto error;
-+
-+ if (!dwc_otg_hcd->flags.b.port_connect_status) {
-+ /*
-+ * The port is disconnected, which means the core is
-+ * either in device mode or it soon will be. Just
-+ * return without doing anything since the port
-+ * register can't be written if the core is in device
-+ * mode.
-+ */
-+ break;
-+ }
-+
-+ switch (wValue) {
-+ case UHF_PORT_SUSPEND:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
-+ if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
-+ goto error;
-+ }
-+ if (core_if->power_down == 2) {
-+ int timeout = 300;
-+ dwc_irqflags_t flags;
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ gusbcfg_data_t gusbcfg = {.d32 = 0 };
-+#ifdef DWC_DEV_SRPCAP
-+ int32_t otg_cap_param = core_if->core_params->otg_cap;
-+#endif
-+ DWC_PRINTF("Preparing for complete power-off\n");
-+
-+ /* Save registers before hibernation */
-+ dwc_otg_save_global_regs(core_if);
-+ dwc_otg_save_host_regs(core_if);
-+
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtsusp = 1;
-+ hprt0.b.prtena = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ /* Spin hprt0.b.prtsusp to became 1 */
-+ do {
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ if (hprt0.b.prtsusp) {
-+ break;
-+ }
-+ dwc_mdelay(1);
-+ } while (--timeout);
-+ if (!timeout) {
-+ DWC_WARN("Suspend wasn't genereted\n");
-+ }
-+ dwc_udelay(10);
-+
-+ /*
-+ * We need to disable interrupts to prevent servicing of any IRQ
-+ * during going to hibernation
-+ */
-+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
-+ core_if->lx_state = DWC_OTG_L2;
-+#ifdef DWC_DEV_SRPCAP
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtpwr = 0;
-+ hprt0.b.prtena = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0,
-+ hprt0.d32);
-+#endif
-+ gusbcfg.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->
-+ gusbcfg);
-+ if (gusbcfg.b.ulpi_utmi_sel == 1) {
-+ /* ULPI interface */
-+ /* Suspend the Phy Clock */
-+ pcgcctl.d32 = 0;
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0,
-+ pcgcctl.d32);
-+ dwc_udelay(10);
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ } else {
-+ /* UTMI+ Interface */
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
-+ dwc_udelay(10);
-+ }
-+#ifdef DWC_DEV_SRPCAP
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.dis_vbus = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+#endif
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ gpwrdn.d32 = 0;
-+#ifdef DWC_DEV_SRPCAP
-+ gpwrdn.b.srp_det_msk = 1;
-+#endif
-+ gpwrdn.b.disconn_det_msk = 1;
-+ gpwrdn.b.lnstchng_msk = 1;
-+ gpwrdn.b.sts_chngint_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Enable Power Down Clamp and all interrupts in GPWRDN */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnclmp = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+ dwc_udelay(10);
-+
-+ /* Switch off VDD */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+
-+#ifdef DWC_DEV_SRPCAP
-+ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
-+ {
-+ core_if->pwron_timer_started = 1;
-+ DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
-+ }
-+#endif
-+ /* Save gpwrdn register for further usage if stschng interrupt */
-+ core_if->gr_backup->gpwrdn_local =
-+ DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
-+
-+ /* Set flag to indicate that we are in hibernation */
-+ core_if->hibernation_suspend = 1;
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
-+
-+ DWC_PRINTF("Host hibernation completed\n");
-+ // Exit from case statement
-+ break;
-+
-+ }
-+ if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
-+ dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+ gotgctl.b.hstsethnpen = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gotgctl, 0, gotgctl.d32);
-+ core_if->op_state = A_SUSPEND;
-+ }
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtsusp = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ {
-+ dwc_irqflags_t flags;
-+ /* Update lx_state */
-+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
-+ core_if->lx_state = DWC_OTG_L2;
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
-+ }
-+ /* Suspend the Phy Clock */
-+ {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, 0,
-+ pcgcctl.d32);
-+ dwc_udelay(10);
-+ }
-+
-+ /* For HNP the bus must be suspended for at least 200ms. */
-+ if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+ dwc_mdelay(200);
-+ }
-+
-+ /** @todo - check how sw can wait for 1 sec to check asesvld??? */
-+#if 0 //vahrama !!!!!!!!!!!!!!!!!!
-+ if (core_if->adp_enable) {
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+ gpwrdn_data_t gpwrdn;
-+
-+ while (gotgctl.b.asesvld == 1) {
-+ gotgctl.d32 =
-+ DWC_READ_REG32(&core_if->
-+ core_global_regs->
-+ gotgctl);
-+ dwc_mdelay(100);
-+ }
-+
-+ /* Enable Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+
-+ /* Unmask SRP detected interrupt from Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.srp_det_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->
-+ gpwrdn, 0, gpwrdn.d32);
-+
-+ dwc_otg_adp_probe_start(core_if);
-+ }
-+#endif
-+ break;
-+ case UHF_PORT_POWER:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "SetPortFeature - USB_PORT_FEAT_POWER\n");
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtpwr = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ break;
-+ case UHF_PORT_RESET:
-+ if ((core_if->power_down == 2)
-+ && (core_if->hibernation_suspend == 1)) {
-+ /* If we are going to exit from Hibernated
-+ * state via USB RESET.
-+ */
-+ dwc_otg_host_hibernation_restore(core_if, 0, 1);
-+ } else {
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+
-+ DWC_DEBUGPL(DBG_HCD,
-+ "DWC OTG HCD HUB CONTROL - "
-+ "SetPortFeature - USB_PORT_FEAT_RESET\n");
-+ {
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ pcgcctl.b.enbl_sleep_gating = 1;
-+ pcgcctl.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
-+ DWC_WRITE_REG32(core_if->pcgcctl, 0);
-+ }
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ {
-+ glpmcfg_data_t lpmcfg;
-+ lpmcfg.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ if (lpmcfg.b.prt_sleep_sts) {
-+ lpmcfg.b.en_utmi_sleep = 0;
-+ lpmcfg.b.hird_thres &= (~(1 << 4));
-+ DWC_WRITE_REG32
-+ (&core_if->core_global_regs->glpmcfg,
-+ lpmcfg.d32);
-+ dwc_mdelay(1);
-+ }
-+ }
-+#endif
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ /* Clear suspend bit if resetting from suspended state. */
-+ hprt0.b.prtsusp = 0;
-+ /* When B-Host the Port reset bit is set in
-+ * the Start HCD Callback function, so that
-+ * the reset is started within 1ms of the HNP
-+ * success interrupt. */
-+ if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
-+ hprt0.b.prtpwr = 1;
-+ hprt0.b.prtrst = 1;
-+ DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
-+ DWC_WRITE_REG32(core_if->host_if->hprt0,
-+ hprt0.d32);
-+ }
-+ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
-+ dwc_mdelay(60);
-+ hprt0.b.prtrst = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
-+ }
-+ break;
-+#ifdef DWC_HS_ELECT_TST
-+ case UHF_PORT_TEST:
-+ {
-+ uint32_t t;
-+ gintmsk_data_t gintmsk;
-+
-+ t = (wIndex >> 8); /* MSB wIndex USB */
-+ DWC_DEBUGPL(DBG_HCD,
-+ "DWC OTG HCD HUB CONTROL - "
-+ "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
-+ t);
-+ DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
-+ if (t < 6) {
-+ hprt0.d32 = dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prttstctl = t;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0,
-+ hprt0.d32);
-+ } else {
-+ /* Setup global vars with reg addresses (quick and
-+ * dirty hack, should be cleaned up)
-+ */
-+ global_regs = core_if->core_global_regs;
-+ hc_global_regs =
-+ core_if->host_if->host_global_regs;
-+ hc_regs =
-+ (dwc_otg_hc_regs_t *) ((char *)
-+ global_regs +
-+ 0x500);
-+ data_fifo =
-+ (uint32_t *) ((char *)global_regs +
-+ 0x1000);
-+
-+ if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
-+ /* Save current interrupt mask */
-+ gintmsk.d32 =
-+ DWC_READ_REG32
-+ (&global_regs->gintmsk);
-+
-+ /* Disable all interrupts while we muck with
-+ * the hardware directly
-+ */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, 0);
-+
-+ /* 15 second delay per the test spec */
-+ dwc_mdelay(15000);
-+
-+ /* Drive suspend on the root port */
-+ hprt0.d32 =
-+ dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtsusp = 1;
-+ hprt0.b.prtres = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ /* 15 second delay per the test spec */
-+ dwc_mdelay(15000);
-+
-+ /* Drive resume on the root port */
-+ hprt0.d32 =
-+ dwc_otg_read_hprt0(core_if);
-+ hprt0.b.prtsusp = 0;
-+ hprt0.b.prtres = 1;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+ dwc_mdelay(100);
-+
-+ /* Clear the resume bit */
-+ hprt0.b.prtres = 0;
-+ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
-+
-+ /* Restore interrupts */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
-+ } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
-+ /* Save current interrupt mask */
-+ gintmsk.d32 =
-+ DWC_READ_REG32
-+ (&global_regs->gintmsk);
-+
-+ /* Disable all interrupts while we muck with
-+ * the hardware directly
-+ */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, 0);
-+
-+ /* 15 second delay per the test spec */
-+ dwc_mdelay(15000);
-+
-+ /* Send the Setup packet */
-+ do_setup();
-+
-+ /* 15 second delay so nothing else happens for awhile */
-+ dwc_mdelay(15000);
-+
-+ /* Restore interrupts */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
-+ } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
-+ /* Save current interrupt mask */
-+ gintmsk.d32 =
-+ DWC_READ_REG32
-+ (&global_regs->gintmsk);
-+
-+ /* Disable all interrupts while we muck with
-+ * the hardware directly
-+ */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, 0);
-+
-+ /* Send the Setup packet */
-+ do_setup();
-+
-+ /* 15 second delay so nothing else happens for awhile */
-+ dwc_mdelay(15000);
-+
-+ /* Send the In and Ack packets */
-+ do_in_ack();
-+
-+ /* 15 second delay so nothing else happens for awhile */
-+ dwc_mdelay(15000);
-+
-+ /* Restore interrupts */
-+ DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
-+ }
-+ }
-+ break;
-+ }
-+#endif /* DWC_HS_ELECT_TST */
-+
-+ case UHF_PORT_INDICATOR:
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
-+ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
-+ /* Not supported */
-+ break;
-+ default:
-+ retval = -DWC_E_INVALID;
-+ DWC_ERROR("DWC OTG HCD - "
-+ "SetPortFeature request %xh "
-+ "unknown or unsupported\n", wValue);
-+ break;
-+ }
-+ break;
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ case UCR_SET_AND_TEST_PORT_FEATURE:
-+ if (wValue != UHF_PORT_L1) {
-+ goto error;
-+ }
-+ {
-+ int portnum, hird, devaddr, remwake;
-+ glpmcfg_data_t lpmcfg;
-+ uint32_t time_usecs;
-+ gintsts_data_t gintsts;
-+ gintmsk_data_t gintmsk;
-+
-+ if (!dwc_otg_get_param_lpm_enable(core_if)) {
-+ goto error;
-+ }
-+ if (wValue != UHF_PORT_L1 || wLength != 1) {
-+ goto error;
-+ }
-+ /* Check if the port currently is in SLEEP state */
-+ lpmcfg.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ if (lpmcfg.b.prt_sleep_sts) {
-+ DWC_INFO("Port is already in sleep mode\n");
-+ buf[0] = 0; /* Return success */
-+ break;
-+ }
-+
-+ portnum = wIndex & 0xf;
-+ hird = (wIndex >> 4) & 0xf;
-+ devaddr = (wIndex >> 8) & 0x7f;
-+ remwake = (wIndex >> 15);
-+
-+ if (portnum != 1) {
-+ retval = -DWC_E_INVALID;
-+ DWC_WARN
-+ ("Wrong port number(%d) in SetandTestPortFeature request\n",
-+ portnum);
-+ break;
-+ }
-+
-+ DWC_PRINTF
-+ ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
-+ portnum, hird, devaddr, remwake);
-+ /* Disable LPM interrupt */
-+ gintmsk.d32 = 0;
-+ gintmsk.b.lpmtranrcvd = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
-+ gintmsk.d32, 0);
-+
-+ if (dwc_otg_hcd_send_lpm
-+ (dwc_otg_hcd, devaddr, hird, remwake)) {
-+ retval = -DWC_E_INVALID;
-+ break;
-+ }
-+
-+ time_usecs = 10 * (lpmcfg.b.retry_count + 1);
-+ /* We will consider timeout if time_usecs microseconds pass,
-+ * and we don't receive LPM transaction status.
-+ * After receiving non-error responce(ACK/NYET/STALL) from device,
-+ * core will set lpmtranrcvd bit.
-+ */
-+ do {
-+ gintsts.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ if (gintsts.b.lpmtranrcvd) {
-+ break;
-+ }
-+ dwc_udelay(1);
-+ } while (--time_usecs);
-+ /* lpm_int bit will be cleared in LPM interrupt handler */
-+
-+ /* Now fill status
-+ * 0x00 - Success
-+ * 0x10 - NYET
-+ * 0x11 - Timeout
-+ */
-+ if (!gintsts.b.lpmtranrcvd) {
-+ buf[0] = 0x3; /* Completion code is Timeout */
-+ dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
-+ } else {
-+ lpmcfg.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ if (lpmcfg.b.lpm_resp == 0x3) {
-+ /* ACK responce from the device */
-+ buf[0] = 0x00; /* Success */
-+ } else if (lpmcfg.b.lpm_resp == 0x2) {
-+ /* NYET responce from the device */
-+ buf[0] = 0x2;
-+ } else {
-+ /* Otherwise responce with Timeout */
-+ buf[0] = 0x3;
-+ }
-+ }
-+ DWC_PRINTF("Device responce to LPM trans is %x\n",
-+ lpmcfg.b.lpm_resp);
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
-+ gintmsk.d32);
-+
-+ break;
-+ }
-+#endif /* CONFIG_USB_DWC_OTG_LPM */
-+ default:
-+error:
-+ retval = -DWC_E_INVALID;
-+ DWC_WARN("DWC OTG HCD - "
-+ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
-+ typeReq, wIndex, wValue);
-+ break;
-+ }
-+
-+ return retval;
-+}
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+/** Returns index of host channel to perform LPM transaction. */
-+int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
-+{
-+ dwc_otg_core_if_t *core_if = hcd->core_if;
-+ dwc_hc_t *hc;
-+ hcchar_data_t hcchar;
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+
-+ if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
-+ DWC_PRINTF("No free channel to select for LPM transaction\n");
-+ return -1;
-+ }
-+
-+ hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
-+
-+ /* Mask host channel interrupts. */
-+ gintmsk.b.hcintr = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
-+
-+ /* Fill fields that core needs for LPM transaction */
-+ hcchar.b.devaddr = devaddr;
-+ hcchar.b.epnum = 0;
-+ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
-+ hcchar.b.mps = 64;
-+ hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
-+ hcchar.b.epdir = 0; /* OUT */
-+ DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
-+ hcchar.d32);
-+
-+ /* Remove the host channel from the free list. */
-+ DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
-+
-+ DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
-+
-+ return hc->hc_num;
-+}
-+
-+/** Release hc after performing LPM transaction */
-+void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
-+{
-+ dwc_hc_t *hc;
-+ glpmcfg_data_t lpmcfg;
-+ uint8_t hc_num;
-+
-+ lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
-+ hc_num = lpmcfg.b.lpm_chan_index;
-+
-+ hc = hcd->hc_ptr_array[hc_num];
-+
-+ DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
-+ /* Return host channel to free list */
-+ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
-+}
-+
-+int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
-+ uint8_t bRemoteWake)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ pcgcctl_data_t pcgcctl = {.d32 = 0 };
-+ int channel;
-+
-+ channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
-+ if (channel < 0) {
-+ return channel;
-+ }
-+
-+ pcgcctl.b.enbl_sleep_gating = 1;
-+ DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
-+
-+ /* Read LPM config register */
-+ lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
-+
-+ /* Program LPM transaction fields */
-+ lpmcfg.b.rem_wkup_en = bRemoteWake;
-+ lpmcfg.b.hird = hird;
-+ lpmcfg.b.hird_thres = 0x1c;
-+ lpmcfg.b.lpm_chan_index = channel;
-+ lpmcfg.b.en_utmi_sleep = 1;
-+ /* Program LPM config register */
-+ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
-+
-+ /* Send LPM transaction */
-+ lpmcfg.b.send_lpm = 1;
-+ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
-+
-+ return 0;
-+}
-+
-+#endif /* CONFIG_USB_DWC_OTG_LPM */
-+
-+int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
-+{
-+ int retval;
-+
-+ if (port != 1) {
-+ return -DWC_E_INVALID;
-+ }
-+
-+ retval = (hcd->flags.b.port_connect_status_change ||
-+ hcd->flags.b.port_reset_change ||
-+ hcd->flags.b.port_enable_change ||
-+ hcd->flags.b.port_suspend_change ||
-+ hcd->flags.b.port_over_current_change);
-+#ifdef DEBUG
-+ if (retval) {
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
-+ " Root port status changed\n");
-+ DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
-+ hcd->flags.b.port_connect_status_change);
-+ DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
-+ hcd->flags.b.port_reset_change);
-+ DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
-+ hcd->flags.b.port_enable_change);
-+ DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
-+ hcd->flags.b.port_suspend_change);
-+ DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
-+ hcd->flags.b.port_over_current_change);
-+ }
-+#endif
-+ return retval;
-+}
-+
-+int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ hfnum_data_t hfnum;
-+ hfnum.d32 =
-+ DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
-+ hfnum);
-+
-+#ifdef DEBUG_SOF
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
-+ hfnum.b.frnum);
-+#endif
-+ return hfnum.b.frnum;
-+}
-+
-+int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
-+ struct dwc_otg_hcd_function_ops *fops)
-+{
-+ int retval = 0;
-+
-+ hcd->fops = fops;
-+ if (!dwc_otg_is_device_mode(hcd->core_if) &&
-+ (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
-+ dwc_otg_hcd_reinit(hcd);
-+ } else {
-+ retval = -DWC_E_NO_DEVICE;
-+ }
-+
-+ return retval;
-+}
-+
-+void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
-+{
-+ return hcd->priv;
-+}
-+
-+void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
-+{
-+ hcd->priv = priv_data;
-+}
-+
-+uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
-+{
-+ return hcd->otg_port;
-+}
-+
-+uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
-+{
-+ uint32_t is_b_host;
-+ if (hcd->core_if->op_state == B_HOST) {
-+ is_b_host = 1;
-+ } else {
-+ is_b_host = 0;
-+ }
-+
-+ return is_b_host;
-+}
-+
-+dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
-+ int iso_desc_count, int atomic_alloc)
-+{
-+ dwc_otg_hcd_urb_t *dwc_otg_urb;
-+ uint32_t size;
-+
-+ size =
-+ sizeof(*dwc_otg_urb) +
-+ iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
-+ if (atomic_alloc)
-+ dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
-+ else
-+ dwc_otg_urb = DWC_ALLOC(size);
-+
-+ if (dwc_otg_urb)
-+ dwc_otg_urb->packet_count = iso_desc_count;
-+ else {
-+ DWC_ERROR("**** DWC OTG HCD URB alloc - "
-+ "%salloc of %db failed\n",
-+ atomic_alloc?"atomic ":"", size);
-+ }
-+ return dwc_otg_urb;
-+}
-+
-+void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ uint8_t dev_addr, uint8_t ep_num,
-+ uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
-+{
-+ dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
-+ ep_type, ep_dir, mps);
-+#if 0
-+ DWC_PRINTF
-+ ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
-+ dev_addr, ep_num, ep_dir, ep_type, mps);
-+#endif
-+}
-+
-+void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ void *urb_handle, void *buf, dwc_dma_t dma,
-+ uint32_t buflen, void *setup_packet,
-+ dwc_dma_t setup_dma, uint32_t flags,
-+ uint16_t interval)
-+{
-+ dwc_otg_urb->priv = urb_handle;
-+ dwc_otg_urb->buf = buf;
-+ dwc_otg_urb->dma = dma;
-+ dwc_otg_urb->length = buflen;
-+ dwc_otg_urb->setup_packet = setup_packet;
-+ dwc_otg_urb->setup_dma = setup_dma;
-+ dwc_otg_urb->flags = flags;
-+ dwc_otg_urb->interval = interval;
-+ dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
-+}
-+
-+uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
-+{
-+ return dwc_otg_urb->status;
-+}
-+
-+uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
-+{
-+ return dwc_otg_urb->actual_length;
-+}
-+
-+uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
-+{
-+ return dwc_otg_urb->error_count;
-+}
-+
-+void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ int desc_num, uint32_t offset,
-+ uint32_t length)
-+{
-+ dwc_otg_urb->iso_descs[desc_num].offset = offset;
-+ dwc_otg_urb->iso_descs[desc_num].length = length;
-+}
-+
-+uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ int desc_num)
-+{
-+ return dwc_otg_urb->iso_descs[desc_num].status;
-+}
-+
-+uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
-+ dwc_otg_urb, int desc_num)
-+{
-+ return dwc_otg_urb->iso_descs[desc_num].actual_length;
-+}
-+
-+int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
-+{
-+ int allocated = 0;
-+ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
-+
-+ if (qh) {
-+ if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
-+ allocated = 1;
-+ }
-+ }
-+ return allocated;
-+}
-+
-+int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
-+{
-+ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
-+ int freed = 0;
-+ DWC_ASSERT(qh, "qh is not allocated\n");
-+
-+ if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
-+ freed = 1;
-+ }
-+
-+ return freed;
-+}
-+
-+uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
-+{
-+ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
-+ DWC_ASSERT(qh, "qh is not allocated\n");
-+ return qh->usecs;
-+}
-+
-+void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
-+{
-+#ifdef DEBUG
-+ int num_channels;
-+ int i;
-+ gnptxsts_data_t np_tx_status;
-+ hptxsts_data_t p_tx_status;
-+
-+ num_channels = hcd->core_if->core_params->host_channels;
-+ DWC_PRINTF("\n");
-+ DWC_PRINTF
-+ ("************************************************************\n");
-+ DWC_PRINTF("HCD State:\n");
-+ DWC_PRINTF(" Num channels: %d\n", num_channels);
-+ for (i = 0; i < num_channels; i++) {
-+ dwc_hc_t *hc = hcd->hc_ptr_array[i];
-+ DWC_PRINTF(" Channel %d:\n", i);
-+ DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
-+ hc->dev_addr, hc->ep_num, hc->ep_is_in);
-+ DWC_PRINTF(" speed: %d\n", hc->speed);
-+ DWC_PRINTF(" ep_type: %d\n", hc->ep_type);
-+ DWC_PRINTF(" max_packet: %d\n", hc->max_packet);
-+ DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start);
-+ DWC_PRINTF(" multi_count: %d\n", hc->multi_count);
-+ DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started);
-+ DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff);
-+ DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len);
-+ DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count);
-+ DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue);
-+ DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending);
-+ DWC_PRINTF(" halt_status: %d\n", hc->halt_status);
-+ DWC_PRINTF(" do_split: %d\n", hc->do_split);
-+ DWC_PRINTF(" complete_split: %d\n", hc->complete_split);
-+ DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr);
-+ DWC_PRINTF(" port_addr: %d\n", hc->port_addr);
-+ DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos);
-+ DWC_PRINTF(" requests: %d\n", hc->requests);
-+ DWC_PRINTF(" qh: %p\n", hc->qh);
-+ if (hc->xfer_started) {
-+ hfnum_data_t hfnum;
-+ hcchar_data_t hcchar;
-+ hctsiz_data_t hctsiz;
-+ hcint_data_t hcint;
-+ hcintmsk_data_t hcintmsk;
-+ hfnum.d32 =
-+ DWC_READ_REG32(&hcd->core_if->
-+ host_if->host_global_regs->hfnum);
-+ hcchar.d32 =
-+ DWC_READ_REG32(&hcd->core_if->host_if->
-+ hc_regs[i]->hcchar);
-+ hctsiz.d32 =
-+ DWC_READ_REG32(&hcd->core_if->host_if->
-+ hc_regs[i]->hctsiz);
-+ hcint.d32 =
-+ DWC_READ_REG32(&hcd->core_if->host_if->
-+ hc_regs[i]->hcint);
-+ hcintmsk.d32 =
-+ DWC_READ_REG32(&hcd->core_if->host_if->
-+ hc_regs[i]->hcintmsk);
-+ DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32);
-+ DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32);
-+ DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32);
-+ DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32);
-+ DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32);
-+ }
-+ if (hc->xfer_started && hc->qh) {
-+ dwc_otg_qtd_t *qtd;
-+ dwc_otg_hcd_urb_t *urb;
-+
-+ DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
-+ if (!qtd->in_process)
-+ break;
-+
-+ urb = qtd->urb;
-+ DWC_PRINTF(" URB Info:\n");
-+ DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb);
-+ if (urb) {
-+ DWC_PRINTF(" Dev: %d, EP: %d %s\n",
-+ dwc_otg_hcd_get_dev_addr(&urb->
-+ pipe_info),
-+ dwc_otg_hcd_get_ep_num(&urb->
-+ pipe_info),
-+ dwc_otg_hcd_is_pipe_in(&urb->
-+ pipe_info) ?
-+ "IN" : "OUT");
-+ DWC_PRINTF(" Max packet size: %d\n",
-+ dwc_otg_hcd_get_mps(&urb->
-+ pipe_info));
-+ DWC_PRINTF(" transfer_buffer: %p\n",
-+ urb->buf);
-+ DWC_PRINTF(" transfer_dma: %p\n",
-+ (void *)urb->dma);
-+ DWC_PRINTF(" transfer_buffer_length: %d\n",
-+ urb->length);
-+ DWC_PRINTF(" actual_length: %d\n",
-+ urb->actual_length);
-+ }
-+ }
-+ }
-+ }
-+ DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels);
-+ DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels);
-+ DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs);
-+ np_tx_status.d32 =
-+ DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
-+ DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n",
-+ np_tx_status.b.nptxqspcavail);
-+ DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n",
-+ np_tx_status.b.nptxfspcavail);
-+ p_tx_status.d32 =
-+ DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
-+ DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n",
-+ p_tx_status.b.ptxqspcavail);
-+ DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
-+ dwc_otg_hcd_dump_frrem(hcd);
-+ dwc_otg_dump_global_registers(hcd->core_if);
-+ dwc_otg_dump_host_registers(hcd->core_if);
-+ DWC_PRINTF
-+ ("************************************************************\n");
-+ DWC_PRINTF("\n");
-+#endif
-+}
-+
-+#ifdef DEBUG
-+void dwc_print_setup_data(uint8_t * setup)
-+{
-+ int i;
-+ if (CHK_DEBUG_LEVEL(DBG_HCD)) {
-+ DWC_PRINTF("Setup Data = MSB ");
-+ for (i = 7; i >= 0; i--)
-+ DWC_PRINTF("%02x ", setup[i]);
-+ DWC_PRINTF("\n");
-+ DWC_PRINTF(" bmRequestType Tranfer = %s\n",
-+ (setup[0] & 0x80) ? "Device-to-Host" :
-+ "Host-to-Device");
-+ DWC_PRINTF(" bmRequestType Type = ");
-+ switch ((setup[0] & 0x60) >> 5) {
-+ case 0:
-+ DWC_PRINTF("Standard\n");
-+ break;
-+ case 1:
-+ DWC_PRINTF("Class\n");
-+ break;
-+ case 2:
-+ DWC_PRINTF("Vendor\n");
-+ break;
-+ case 3:
-+ DWC_PRINTF("Reserved\n");
-+ break;
-+ }
-+ DWC_PRINTF(" bmRequestType Recipient = ");
-+ switch (setup[0] & 0x1f) {
-+ case 0:
-+ DWC_PRINTF("Device\n");
-+ break;
-+ case 1:
-+ DWC_PRINTF("Interface\n");
-+ break;
-+ case 2:
-+ DWC_PRINTF("Endpoint\n");
-+ break;
-+ case 3:
-+ DWC_PRINTF("Other\n");
-+ break;
-+ default:
-+ DWC_PRINTF("Reserved\n");
-+ break;
-+ }
-+ DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]);
-+ DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
-+ DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
-+ DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
-+ }
-+}
-+#endif
-+
-+void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
-+{
-+#if 0
-+ DWC_PRINTF("Frame remaining at SOF:\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->frrem_samples, hcd->frrem_accum,
-+ (hcd->frrem_samples > 0) ?
-+ hcd->frrem_accum / hcd->frrem_samples : 0);
-+
-+ DWC_PRINTF("\n");
-+ DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->core_if->hfnum_7_samples,
-+ hcd->core_if->hfnum_7_frrem_accum,
-+ (hcd->core_if->hfnum_7_samples >
-+ 0) ? hcd->core_if->hfnum_7_frrem_accum /
-+ hcd->core_if->hfnum_7_samples : 0);
-+ DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->core_if->hfnum_0_samples,
-+ hcd->core_if->hfnum_0_frrem_accum,
-+ (hcd->core_if->hfnum_0_samples >
-+ 0) ? hcd->core_if->hfnum_0_frrem_accum /
-+ hcd->core_if->hfnum_0_samples : 0);
-+ DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->core_if->hfnum_other_samples,
-+ hcd->core_if->hfnum_other_frrem_accum,
-+ (hcd->core_if->hfnum_other_samples >
-+ 0) ? hcd->core_if->hfnum_other_frrem_accum /
-+ hcd->core_if->hfnum_other_samples : 0);
-+
-+ DWC_PRINTF("\n");
-+ DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
-+ (hcd->hfnum_7_samples_a > 0) ?
-+ hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
-+ DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
-+ (hcd->hfnum_0_samples_a > 0) ?
-+ hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
-+ DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
-+ (hcd->hfnum_other_samples_a > 0) ?
-+ hcd->hfnum_other_frrem_accum_a /
-+ hcd->hfnum_other_samples_a : 0);
-+
-+ DWC_PRINTF("\n");
-+ DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
-+ (hcd->hfnum_7_samples_b > 0) ?
-+ hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
-+ DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
-+ (hcd->hfnum_0_samples_b > 0) ?
-+ hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
-+ DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
-+ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n",
-+ hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
-+ (hcd->hfnum_other_samples_b > 0) ?
-+ hcd->hfnum_other_frrem_accum_b /
-+ hcd->hfnum_other_samples_b : 0);
-+#endif
-+}
-+
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1132 @@
-+/*==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
-+ * $Revision: #10 $
-+ * $Date: 2011/10/20 $
-+ * $Change: 1869464 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+
-+/** @file
-+ * This file contains Descriptor DMA support implementation for host mode.
-+ */
-+
-+#include "dwc_otg_hcd.h"
-+#include "dwc_otg_regs.h"
-+
-+extern bool microframe_schedule;
-+
-+static inline uint8_t frame_list_idx(uint16_t frame)
-+{
-+ return (frame & (MAX_FRLIST_EN_NUM - 1));
-+}
-+
-+static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
-+{
-+ return (idx + inc) &
-+ (((speed ==
-+ DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
-+ MAX_DMA_DESC_NUM_GENERIC) - 1);
-+}
-+
-+static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
-+{
-+ return (idx - inc) &
-+ (((speed ==
-+ DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC :
-+ MAX_DMA_DESC_NUM_GENERIC) - 1);
-+}
-+
-+static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
-+{
-+ return (((qh->ep_type == UE_ISOCHRONOUS)
-+ && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH))
-+ ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC);
-+}
-+static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
-+{
-+ return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)
-+ ? ((qh->interval + 8 - 1) / 8)
-+ : qh->interval);
-+}
-+
-+static int desc_list_alloc(dwc_otg_qh_t * qh)
-+{
-+ int retval = 0;
-+
-+ qh->desc_list = (dwc_otg_host_dma_desc_t *)
-+ DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
-+ &qh->desc_list_dma);
-+
-+ if (!qh->desc_list) {
-+ retval = -DWC_E_NO_MEMORY;
-+ DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
-+
-+ }
-+
-+ dwc_memset(qh->desc_list, 0x00,
-+ sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
-+
-+ qh->n_bytes =
-+ (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh));
-+
-+ if (!qh->n_bytes) {
-+ retval = -DWC_E_NO_MEMORY;
-+ DWC_ERROR
-+ ("%s: Failed to allocate array for descriptors' size actual values\n",
-+ __func__);
-+
-+ }
-+ return retval;
-+
-+}
-+
-+static void desc_list_free(dwc_otg_qh_t * qh)
-+{
-+ if (qh->desc_list) {
-+ DWC_DMA_FREE(max_desc_num(qh), qh->desc_list,
-+ qh->desc_list_dma);
-+ qh->desc_list = NULL;
-+ }
-+
-+ if (qh->n_bytes) {
-+ DWC_FREE(qh->n_bytes);
-+ qh->n_bytes = NULL;
-+ }
-+}
-+
-+static int frame_list_alloc(dwc_otg_hcd_t * hcd)
-+{
-+ int retval = 0;
-+ if (hcd->frame_list)
-+ return 0;
-+
-+ hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM,
-+ &hcd->frame_list_dma);
-+ if (!hcd->frame_list) {
-+ retval = -DWC_E_NO_MEMORY;
-+ DWC_ERROR("%s: Frame List allocation failed\n", __func__);
-+ }
-+
-+ dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
-+
-+ return retval;
-+}
-+
-+static void frame_list_free(dwc_otg_hcd_t * hcd)
-+{
-+ if (!hcd->frame_list)
-+ return;
-+
-+ DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
-+ hcd->frame_list = NULL;
-+}
-+
-+static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
-+{
-+
-+ hcfg_data_t hcfg;
-+
-+ hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
-+
-+ if (hcfg.b.perschedena) {
-+ /* already enabled */
-+ return;
-+ }
-+
-+ DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr,
-+ hcd->frame_list_dma);
-+
-+ switch (fr_list_en) {
-+ case 64:
-+ hcfg.b.frlisten = 3;
-+ break;
-+ case 32:
-+ hcfg.b.frlisten = 2;
-+ break;
-+ case 16:
-+ hcfg.b.frlisten = 1;
-+ break;
-+ case 8:
-+ hcfg.b.frlisten = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ hcfg.b.perschedena = 1;
-+
-+ DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
-+ DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
-+
-+}
-+
-+static void per_sched_disable(dwc_otg_hcd_t * hcd)
-+{
-+ hcfg_data_t hcfg;
-+
-+ hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg);
-+
-+ if (!hcfg.b.perschedena) {
-+ /* already disabled */
-+ return;
-+ }
-+ hcfg.b.perschedena = 0;
-+
-+ DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
-+ DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
-+}
-+
-+/*
-+ * Activates/Deactivates FrameList entries for the channel
-+ * based on endpoint servicing period.
-+ */
-+void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
-+{
-+ uint16_t i, j, inc;
-+ dwc_hc_t *hc = NULL;
-+
-+ if (!qh->channel) {
-+ DWC_ERROR("qh->channel = %p", qh->channel);
-+ return;
-+ }
-+
-+ if (!hcd) {
-+ DWC_ERROR("------hcd = %p", hcd);
-+ return;
-+ }
-+
-+ if (!hcd->frame_list) {
-+ DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list);
-+ return;
-+ }
-+
-+ hc = qh->channel;
-+ inc = frame_incr_val(qh);
-+ if (qh->ep_type == UE_ISOCHRONOUS)
-+ i = frame_list_idx(qh->sched_frame);
-+ else
-+ i = 0;
-+
-+ j = i;
-+ do {
-+ if (enable)
-+ hcd->frame_list[j] |= (1 << hc->hc_num);
-+ else
-+ hcd->frame_list[j] &= ~(1 << hc->hc_num);
-+ j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
-+ }
-+ while (j != i);
-+ if (!enable)
-+ return;
-+ hc->schinfo = 0;
-+ if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
-+ j = 1;
-+ /* TODO - check this */
-+ inc = (8 + qh->interval - 1) / qh->interval;
-+ for (i = 0; i < inc; i++) {
-+ hc->schinfo |= j;
-+ j = j << qh->interval;
-+ }
-+ } else {
-+ hc->schinfo = 0xff;
-+ }
-+}
-+
-+#if 1
-+void dump_frame_list(dwc_otg_hcd_t * hcd)
-+{
-+ int i = 0;
-+ DWC_PRINTF("--FRAME LIST (hex) --\n");
-+ for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
-+ DWC_PRINTF("%x\t", hcd->frame_list[i]);
-+ if (!(i % 8) && i)
-+ DWC_PRINTF("\n");
-+ }
-+ DWC_PRINTF("\n----\n");
-+
-+}
-+#endif
-+
-+static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ dwc_irqflags_t flags;
-+ dwc_spinlock_t *channel_lock = hcd->channel_lock;
-+
-+ dwc_hc_t *hc = qh->channel;
-+ if (dwc_qh_is_non_per(qh)) {
-+ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
-+ if (!microframe_schedule)
-+ hcd->non_periodic_channels--;
-+ else
-+ hcd->available_host_channels++;
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+ } else
-+ update_frame_list(hcd, qh, 0);
-+
-+ /*
-+ * The condition is added to prevent double cleanup try in case of device
-+ * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
-+ */
-+ if (hc->qh) {
-+ dwc_otg_hc_cleanup(hcd->core_if, hc);
-+ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
-+ hc->qh = NULL;
-+ }
-+
-+ qh->channel = NULL;
-+ qh->ntd = 0;
-+
-+ if (qh->desc_list) {
-+ dwc_memset(qh->desc_list, 0x00,
-+ sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
-+ }
-+}
-+
-+/**
-+ * Initializes a QH structure's Descriptor DMA related members.
-+ * Allocates memory for descriptor list.
-+ * On first periodic QH, allocates memory for FrameList
-+ * and enables periodic scheduling.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh The QH to init.
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ int retval = 0;
-+
-+ if (qh->do_split) {
-+ DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
-+ return -1;
-+ }
-+
-+ retval = desc_list_alloc(qh);
-+
-+ if ((retval == 0)
-+ && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
-+ if (!hcd->frame_list) {
-+ retval = frame_list_alloc(hcd);
-+ /* Enable periodic schedule on first periodic QH */
-+ if (retval == 0)
-+ per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
-+ }
-+ }
-+
-+ qh->ntd = 0;
-+
-+ return retval;
-+}
-+
-+/**
-+ * Frees descriptor list memory associated with the QH.
-+ * If QH is periodic and the last, frees FrameList memory
-+ * and disables periodic scheduling.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh The QH to init.
-+ */
-+void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ desc_list_free(qh);
-+
-+ /*
-+ * Channel still assigned due to some reasons.
-+ * Seen on Isoc URB dequeue. Channel halted but no subsequent
-+ * ChHalted interrupt to release the channel. Afterwards
-+ * when it comes here from endpoint disable routine
-+ * channel remains assigned.
-+ */
-+ if (qh->channel)
-+ release_channel_ddma(hcd, qh);
-+
-+ if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
-+ && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
-+
-+ per_sched_disable(hcd);
-+ frame_list_free(hcd);
-+ }
-+}
-+
-+static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
-+{
-+ if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
-+ /*
-+ * Descriptor set(8 descriptors) index
-+ * which is 8-aligned.
-+ */
-+ return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
-+ } else {
-+ return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
-+ }
-+}
-+
-+/*
-+ * Determine starting frame for Isochronous transfer.
-+ * Few frames skipped to prevent race condition with HC.
-+ */
-+static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
-+ uint8_t * skip_frames)
-+{
-+ uint16_t frame = 0;
-+ hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
-+
-+ /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
-+
-+ /*
-+ * skip_frames is used to limit activated descriptors number
-+ * to avoid the situation when HC services the last activated
-+ * descriptor firstly.
-+ * Example for FS:
-+ * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
-+ * corresponding to curr_frame+1, the descriptor corresponding to frame 2
-+ * will be fetched. If the number of descriptors is max=64 (or greather) the
-+ * list will be fully programmed with Active descriptors and it is possible
-+ * case(rare) that the latest descriptor(considering rollback) corresponding
-+ * to frame 2 will be serviced first. HS case is more probable because, in fact,
-+ * up to 11 uframes(16 in the code) may be skipped.
-+ */
-+ if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
-+ /*
-+ * Consider uframe counter also, to start xfer asap.
-+ * If half of the frame elapsed skip 2 frames otherwise
-+ * just 1 frame.
-+ * Starting descriptor index must be 8-aligned, so
-+ * if the current frame is near to complete the next one
-+ * is skipped as well.
-+ */
-+
-+ if (dwc_micro_frame_num(hcd->frame_number) >= 5) {
-+ *skip_frames = 2 * 8;
-+ frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
-+ } else {
-+ *skip_frames = 1 * 8;
-+ frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
-+ }
-+
-+ frame = dwc_full_frame_num(frame);
-+ } else {
-+ /*
-+ * Two frames are skipped for FS - the current and the next.
-+ * But for descriptor programming, 1 frame(descriptor) is enough,
-+ * see example above.
-+ */
-+ *skip_frames = 1;
-+ frame = dwc_frame_num_inc(hcd->frame_number, 2);
-+ }
-+
-+ return frame;
-+}
-+
-+/*
-+ * Calculate initial descriptor index for isochronous transfer
-+ * based on scheduled frame.
-+ */
-+static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ uint16_t frame = 0, fr_idx, fr_idx_tmp;
-+ uint8_t skip_frames = 0;
-+ /*
-+ * With current ISOC processing algorithm the channel is being
-+ * released when no more QTDs in the list(qh->ntd == 0).
-+ * Thus this function is called only when qh->ntd == 0 and qh->channel == 0.
-+ *
-+ * So qh->channel != NULL branch is not used and just not removed from the
-+ * source file. It is required for another possible approach which is,
-+ * do not disable and release the channel when ISOC session completed,
-+ * just move QH to inactive schedule until new QTD arrives.
-+ * On new QTD, the QH moved back to 'ready' schedule,
-+ * starting frame and therefore starting desc_index are recalculated.
-+ * In this case channel is released only on ep_disable.
-+ */
-+
-+ /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
-+ if (qh->channel) {
-+ frame = calc_starting_frame(hcd, qh, &skip_frames);
-+ /*
-+ * Calculate initial descriptor index based on FrameList current bitmap
-+ * and servicing period.
-+ */
-+ fr_idx_tmp = frame_list_idx(frame);
-+ fr_idx =
-+ (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) -
-+ fr_idx_tmp)
-+ % frame_incr_val(qh);
-+ fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
-+ } else {
-+ qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);
-+ fr_idx = frame_list_idx(qh->sched_frame);
-+ }
-+
-+ qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx);
-+
-+ return skip_frames;
-+}
-+
-+#define ISOC_URB_GIVEBACK_ASAP
-+
-+#define MAX_ISOC_XFER_SIZE_FS 1023
-+#define MAX_ISOC_XFER_SIZE_HS 3072
-+#define DESCNUM_THRESHOLD 4
-+
-+static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
-+ uint8_t skip_frames)
-+{
-+ struct dwc_otg_hcd_iso_packet_desc *frame_desc;
-+ dwc_otg_qtd_t *qtd;
-+ dwc_otg_host_dma_desc_t *dma_desc;
-+ uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
-+
-+ idx = qh->td_last;
-+ inc = qh->interval;
-+ n_desc = 0;
-+
-+ ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
-+ if (skip_frames && !qh->channel)
-+ ntd_max = ntd_max - skip_frames / qh->interval;
-+
-+ max_xfer_size =
-+ (qh->dev_speed ==
-+ DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS :
-+ MAX_ISOC_XFER_SIZE_FS;
-+
-+ DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
-+ while ((qh->ntd < ntd_max)
-+ && (qtd->isoc_frame_index_last <
-+ qtd->urb->packet_count)) {
-+
-+ dma_desc = &qh->desc_list[idx];
-+ dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
-+
-+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
-+
-+ if (frame_desc->length > max_xfer_size)
-+ qh->n_bytes[idx] = max_xfer_size;
-+ else
-+ qh->n_bytes[idx] = frame_desc->length;
-+ dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
-+ dma_desc->status.b_isoc.a = 1;
-+ dma_desc->status.b_isoc.sts = 0;
-+
-+ dma_desc->buf = qtd->urb->dma + frame_desc->offset;
-+
-+ qh->ntd++;
-+
-+ qtd->isoc_frame_index_last++;
-+
-+#ifdef ISOC_URB_GIVEBACK_ASAP
-+ /*
-+ * Set IOC for each descriptor corresponding to the
-+ * last frame of the URB.
-+ */
-+ if (qtd->isoc_frame_index_last ==
-+ qtd->urb->packet_count)
-+ dma_desc->status.b_isoc.ioc = 1;
-+
-+#endif
-+ idx = desclist_idx_inc(idx, inc, qh->dev_speed);
-+ n_desc++;
-+
-+ }
-+ qtd->in_process = 1;
-+ }
-+
-+ qh->td_last = idx;
-+
-+#ifdef ISOC_URB_GIVEBACK_ASAP
-+ /* Set IOC for the last descriptor if descriptor list is full */
-+ if (qh->ntd == ntd_max) {
-+ idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
-+ qh->desc_list[idx].status.b_isoc.ioc = 1;
-+ }
-+#else
-+ /*
-+ * Set IOC bit only for one descriptor.
-+ * Always try to be ahead of HW processing,
-+ * i.e. on IOC generation driver activates next descriptors but
-+ * core continues to process descriptors followed the one with IOC set.
-+ */
-+
-+ if (n_desc > DESCNUM_THRESHOLD) {
-+ /*
-+ * Move IOC "up". Required even if there is only one QTD
-+ * in the list, cause QTDs migth continue to be queued,
-+ * but during the activation it was only one queued.
-+ * Actually more than one QTD might be in the list if this function called
-+ * from XferCompletion - QTDs was queued during HW processing of the previous
-+ * descriptor chunk.
-+ */
-+ idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
-+ } else {
-+ /*
-+ * Set the IOC for the latest descriptor
-+ * if either number of descriptor is not greather than threshold
-+ * or no more new descriptors activated.
-+ */
-+ idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
-+ }
-+
-+ qh->desc_list[idx].status.b_isoc.ioc = 1;
-+#endif
-+}
-+
-+static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+
-+ dwc_hc_t *hc;
-+ dwc_otg_host_dma_desc_t *dma_desc;
-+ dwc_otg_qtd_t *qtd;
-+ int num_packets, len, n_desc = 0;
-+
-+ hc = qh->channel;
-+
-+ /*
-+ * Start with hc->xfer_buff initialized in
-+ * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
-+ * this pointer re-assigned to the buffer of the currently processed QTD.
-+ * For non-SG request there is always one QTD active.
-+ */
-+
-+ DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
-+
-+ if (n_desc) {
-+ /* SG request - more than 1 QTDs */
-+ hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
-+ hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
-+ }
-+
-+ qtd->n_desc = 0;
-+
-+ do {
-+ dma_desc = &qh->desc_list[n_desc];
-+ len = hc->xfer_len;
-+
-+ if (len > MAX_DMA_DESC_SIZE)
-+ len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
-+
-+ if (hc->ep_is_in) {
-+ if (len > 0) {
-+ num_packets = (len + hc->max_packet - 1) / hc->max_packet;
-+ } else {
-+ /* Need 1 packet for transfer length of 0. */
-+ num_packets = 1;
-+ }
-+ /* Always program an integral # of max packets for IN transfers. */
-+ len = num_packets * hc->max_packet;
-+ }
-+
-+ dma_desc->status.b.n_bytes = len;
-+
-+ qh->n_bytes[n_desc] = len;
-+
-+ if ((qh->ep_type == UE_CONTROL)
-+ && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
-+ dma_desc->status.b.sup = 1; /* Setup Packet */
-+
-+ dma_desc->status.b.a = 1; /* Active descriptor */
-+ dma_desc->status.b.sts = 0;
-+
-+ dma_desc->buf =
-+ ((unsigned long)hc->xfer_buff & 0xffffffff);
-+
-+ /*
-+ * Last descriptor(or single) of IN transfer
-+ * with actual size less than MaxPacket.
-+ */
-+ if (len > hc->xfer_len) {
-+ hc->xfer_len = 0;
-+ } else {
-+ hc->xfer_buff += len;
-+ hc->xfer_len -= len;
-+ }
-+
-+ qtd->n_desc++;
-+ n_desc++;
-+ }
-+ while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
-+
-+
-+ qtd->in_process = 1;
-+
-+ if (qh->ep_type == UE_CONTROL)
-+ break;
-+
-+ if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
-+ break;
-+ }
-+
-+ if (n_desc) {
-+ /* Request Transfer Complete interrupt for the last descriptor */
-+ qh->desc_list[n_desc - 1].status.b.ioc = 1;
-+ /* End of List indicator */
-+ qh->desc_list[n_desc - 1].status.b.eol = 1;
-+
-+ hc->ntd = n_desc;
-+ }
-+}
-+
-+/**
-+ * For Control and Bulk endpoints initializes descriptor list
-+ * and starts the transfer.
-+ *
-+ * For Interrupt and Isochronous endpoints initializes descriptor list
-+ * then updates FrameList, marking appropriate entries as active.
-+ * In case of Isochronous, the starting descriptor index is calculated based
-+ * on the scheduled frame, but only on the first transfer descriptor within a session.
-+ * Then starts the transfer via enabling the channel.
-+ * For Isochronous endpoint the channel is not halted on XferComplete
-+ * interrupt so remains assigned to the endpoint(QH) until session is done.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh The QH to init.
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ /* Channel is already assigned */
-+ dwc_hc_t *hc = qh->channel;
-+ uint8_t skip_frames = 0;
-+
-+ switch (hc->ep_type) {
-+ case DWC_OTG_EP_TYPE_CONTROL:
-+ case DWC_OTG_EP_TYPE_BULK:
-+ init_non_isoc_dma_desc(hcd, qh);
-+
-+ dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
-+ break;
-+ case DWC_OTG_EP_TYPE_INTR:
-+ init_non_isoc_dma_desc(hcd, qh);
-+
-+ update_frame_list(hcd, qh, 1);
-+
-+ dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
-+ break;
-+ case DWC_OTG_EP_TYPE_ISOC:
-+
-+ if (!qh->ntd)
-+ skip_frames = recalc_initial_desc_idx(hcd, qh);
-+
-+ init_isoc_dma_desc(hcd, qh, skip_frames);
-+
-+ if (!hc->xfer_started) {
-+
-+ update_frame_list(hcd, qh, 1);
-+
-+ /*
-+ * Always set to max, instead of actual size.
-+ * Otherwise ntd will be changed with
-+ * channel being enabled. Not recommended.
-+ *
-+ */
-+ hc->ntd = max_desc_num(qh);
-+ /* Enable channel only once for ISOC */
-+ dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
-+ }
-+
-+ break;
-+ default:
-+
-+ break;
-+ }
-+}
-+
-+static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ struct dwc_otg_hcd_iso_packet_desc *frame_desc;
-+ dwc_otg_qtd_t *qtd, *qtd_tmp;
-+ dwc_otg_qh_t *qh;
-+ dwc_otg_host_dma_desc_t *dma_desc;
-+ uint16_t idx, remain;
-+ uint8_t urb_compl;
-+
-+ qh = hc->qh;
-+ idx = qh->td_first;
-+
-+ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
-+ qtd->in_process = 0;
-+ return;
-+ } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) ||
-+ (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
-+ /*
-+ * Channel is halted in these error cases.
-+ * Considered as serious issues.
-+ * Complete all URBs marking all frames as failed,
-+ * irrespective whether some of the descriptors(frames) succeeded or no.
-+ * Pass error code to completion routine as well, to
-+ * update urb->status, some of class drivers might use it to stop
-+ * queing transfer requests.
-+ */
-+ int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR)
-+ ? (-DWC_E_IO)
-+ : (-DWC_E_OVERFLOW);
-+
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
-+ for (idx = 0; idx < qtd->urb->packet_count; idx++) {
-+ frame_desc = &qtd->urb->iso_descs[idx];
-+ frame_desc->status = err;
-+ }
-+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
-+ }
-+ return;
-+ }
-+
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
-+
-+ if (!qtd->in_process)
-+ break;
-+
-+ urb_compl = 0;
-+
-+ do {
-+
-+ dma_desc = &qh->desc_list[idx];
-+
-+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
-+ remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
-+
-+ if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
-+ /*
-+ * XactError or, unable to complete all the transactions
-+ * in the scheduled micro-frame/frame,
-+ * both indicated by DMA_DESC_STS_PKTERR.
-+ */
-+ qtd->urb->error_count++;
-+ frame_desc->actual_length = qh->n_bytes[idx] - remain;
-+ frame_desc->status = -DWC_E_PROTOCOL;
-+ } else {
-+ /* Success */
-+
-+ frame_desc->actual_length = qh->n_bytes[idx] - remain;
-+ frame_desc->status = 0;
-+ }
-+
-+ if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
-+ /*
-+ * urb->status is not used for isoc transfers here.
-+ * The individual frame_desc status are used instead.
-+ */
-+
-+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
-+
-+ /*
-+ * This check is necessary because urb_dequeue can be called
-+ * from urb complete callback(sound driver example).
-+ * All pending URBs are dequeued there, so no need for
-+ * further processing.
-+ */
-+ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
-+ return;
-+ }
-+
-+ urb_compl = 1;
-+
-+ }
-+
-+ qh->ntd--;
-+
-+ /* Stop if IOC requested descriptor reached */
-+ if (dma_desc->status.b_isoc.ioc) {
-+ idx = desclist_idx_inc(idx, qh->interval, hc->speed);
-+ goto stop_scan;
-+ }
-+
-+ idx = desclist_idx_inc(idx, qh->interval, hc->speed);
-+
-+ if (urb_compl)
-+ break;
-+ }
-+ while (idx != qh->td_first);
-+ }
-+stop_scan:
-+ qh->td_first = idx;
-+}
-+
-+uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_host_dma_desc_t * dma_desc,
-+ dwc_otg_halt_status_e halt_status,
-+ uint32_t n_bytes, uint8_t * xfer_done)
-+{
-+
-+ uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
-+ dwc_otg_hcd_urb_t *urb = qtd->urb;
-+
-+ if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
-+ urb->status = -DWC_E_IO;
-+ return 1;
-+ }
-+ if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
-+ switch (halt_status) {
-+ case DWC_OTG_HC_XFER_STALL:
-+ urb->status = -DWC_E_PIPE;
-+ break;
-+ case DWC_OTG_HC_XFER_BABBLE_ERR:
-+ urb->status = -DWC_E_OVERFLOW;
-+ break;
-+ case DWC_OTG_HC_XFER_XACT_ERR:
-+ urb->status = -DWC_E_PROTOCOL;
-+ break;
-+ default:
-+ DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
-+ halt_status);
-+ break;
-+ }
-+ return 1;
-+ }
-+
-+ if (dma_desc->status.b.a == 1) {
-+ DWC_DEBUGPL(DBG_HCDV,
-+ "Active descriptor encountered on channel %d\n",
-+ hc->hc_num);
-+ return 0;
-+ }
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
-+ if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
-+ urb->actual_length += n_bytes - remain;
-+ if (remain || urb->actual_length == urb->length) {
-+ /*
-+ * For Control Data stage do not set urb->status=0 to prevent
-+ * URB callback. Set it when Status phase done. See below.
-+ */
-+ *xfer_done = 1;
-+ }
-+
-+ } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
-+ urb->status = 0;
-+ *xfer_done = 1;
-+ }
-+ /* No handling for SETUP stage */
-+ } else {
-+ /* BULK and INTR */
-+ urb->actual_length += n_bytes - remain;
-+ if (remain || urb->actual_length == urb->length) {
-+ urb->status = 0;
-+ *xfer_done = 1;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ dwc_otg_hcd_urb_t *urb = NULL;
-+ dwc_otg_qtd_t *qtd, *qtd_tmp;
-+ dwc_otg_qh_t *qh;
-+ dwc_otg_host_dma_desc_t *dma_desc;
-+ uint32_t n_bytes, n_desc, i;
-+ uint8_t failed = 0, xfer_done;
-+
-+ n_desc = 0;
-+
-+ qh = hc->qh;
-+
-+ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
-+ qtd->in_process = 0;
-+ }
-+ return;
-+ }
-+
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
-+
-+ urb = qtd->urb;
-+
-+ n_bytes = 0;
-+ xfer_done = 0;
-+
-+ for (i = 0; i < qtd->n_desc; i++) {
-+ dma_desc = &qh->desc_list[n_desc];
-+
-+ n_bytes = qh->n_bytes[n_desc];
-+
-+ failed =
-+ update_non_isoc_urb_state_ddma(hcd, hc, qtd,
-+ dma_desc,
-+ halt_status, n_bytes,
-+ &xfer_done);
-+
-+ if (failed
-+ || (xfer_done
-+ && (urb->status != -DWC_E_IN_PROGRESS))) {
-+
-+ hcd->fops->complete(hcd, urb->priv, urb,
-+ urb->status);
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
-+
-+ if (failed)
-+ goto stop_scan;
-+ } else if (qh->ep_type == UE_CONTROL) {
-+ if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
-+ if (urb->length > 0) {
-+ qtd->control_phase = DWC_OTG_CONTROL_DATA;
-+ } else {
-+ qtd->control_phase = DWC_OTG_CONTROL_STATUS;
-+ }
-+ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
-+ } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
-+ if (xfer_done) {
-+ qtd->control_phase = DWC_OTG_CONTROL_STATUS;
-+ DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
-+ } else if (i + 1 == qtd->n_desc) {
-+ /*
-+ * Last descriptor for Control data stage which is
-+ * not completed yet.
-+ */
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ }
-+ }
-+ }
-+
-+ n_desc++;
-+ }
-+
-+ }
-+
-+stop_scan:
-+
-+ if (qh->ep_type != UE_CONTROL) {
-+ /*
-+ * Resetting the data toggle for bulk
-+ * and interrupt endpoints in case of stall. See handle_hc_stall_intr()
-+ */
-+ if (halt_status == DWC_OTG_HC_XFER_STALL)
-+ qh->data_toggle = DWC_OTG_HC_PID_DATA0;
-+ else
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ }
-+
-+ if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
-+ hcint_data_t hcint;
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ if (hcint.b.nyet) {
-+ /*
-+ * Got a NYET on the last transaction of the transfer. It
-+ * means that the endpoint should be in the PING state at the
-+ * beginning of the next transfer.
-+ */
-+ qh->ping_state = 1;
-+ clear_hc_int(hc_regs, nyet);
-+ }
-+
-+ }
-+
-+}
-+
-+/**
-+ * This function is called from interrupt handlers.
-+ * Scans the descriptor list, updates URB's status and
-+ * calls completion routine for the URB if it's done.
-+ * Releases the channel to be used by other transfers.
-+ * In case of Isochronous endpoint the channel is not halted until
-+ * the end of the session, i.e. QTD list is empty.
-+ * If periodic channel released the FrameList is updated accordingly.
-+ *
-+ * Calls transaction selection routines to activate pending transfers.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param hc Host channel, the transfer is completed on.
-+ * @param hc_regs Host channel registers.
-+ * @param halt_status Reason the channel is being halted,
-+ * or just XferComplete for isochronous transfer
-+ */
-+void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ uint8_t continue_isoc_xfer = 0;
-+ dwc_otg_transaction_type_e tr_type;
-+ dwc_otg_qh_t *qh = hc->qh;
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+
-+ complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
-+
-+ /* Release the channel if halted or session completed */
-+ if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
-+ DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
-+
-+ /* Halt the channel if session completed */
-+ if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
-+ dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
-+ }
-+
-+ release_channel_ddma(hcd, qh);
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+ } else {
-+ /* Keep in assigned schedule to continue transfer */
-+ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
-+ &qh->qh_list_entry);
-+ continue_isoc_xfer = 1;
-+
-+ }
-+ /** @todo Consider the case when period exceeds FrameList size.
-+ * Frame Rollover interrupt should be used.
-+ */
-+ } else {
-+ /* Scan descriptor list to complete the URB(s), then release the channel */
-+ complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
-+
-+ release_channel_ddma(hcd, qh);
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+
-+ if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
-+ /* Add back to inactive non-periodic schedule on normal completion */
-+ dwc_otg_hcd_qh_add(hcd, qh);
-+ }
-+
-+ }
-+ tr_type = dwc_otg_hcd_select_transactions(hcd);
-+ if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
-+ if (continue_isoc_xfer) {
-+ if (tr_type == DWC_OTG_TRANSACTION_NONE) {
-+ tr_type = DWC_OTG_TRANSACTION_PERIODIC;
-+ } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
-+ tr_type = DWC_OTG_TRANSACTION_ALL;
-+ }
-+ }
-+ dwc_otg_hcd_queue_transactions(hcd, tr_type);
-+ }
-+}
-+
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,851 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
-+ * $Revision: #58 $
-+ * $Date: 2011/09/15 $
-+ * $Change: 1846647 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+#ifndef __DWC_HCD_H__
-+#define __DWC_HCD_H__
-+
-+#include "dwc_otg_os_dep.h"
-+#include "usb.h"
-+#include "dwc_otg_hcd_if.h"
-+#include "dwc_otg_core_if.h"
-+#include "dwc_list.h"
-+#include "dwc_otg_cil.h"
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the structures, constants, and interfaces for
-+ * the Host Contoller Driver (HCD).
-+ *
-+ * The Host Controller Driver (HCD) is responsible for translating requests
-+ * from the USB Driver into the appropriate actions on the DWC_otg controller.
-+ * It isolates the USBD from the specifics of the controller by providing an
-+ * API to the USBD.
-+ */
-+
-+struct dwc_otg_hcd_pipe_info {
-+ uint8_t dev_addr;
-+ uint8_t ep_num;
-+ uint8_t pipe_type;
-+ uint8_t pipe_dir;
-+ uint16_t mps;
-+};
-+
-+struct dwc_otg_hcd_iso_packet_desc {
-+ uint32_t offset;
-+ uint32_t length;
-+ uint32_t actual_length;
-+ uint32_t status;
-+};
-+
-+struct dwc_otg_qtd;
-+
-+struct dwc_otg_hcd_urb {
-+ void *priv;
-+ struct dwc_otg_qtd *qtd;
-+ void *buf;
-+ dwc_dma_t dma;
-+ void *setup_packet;
-+ dwc_dma_t setup_dma;
-+ uint32_t length;
-+ uint32_t actual_length;
-+ uint32_t status;
-+ uint32_t error_count;
-+ uint32_t packet_count;
-+ uint32_t flags;
-+ uint16_t interval;
-+ struct dwc_otg_hcd_pipe_info pipe_info;
-+ struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
-+};
-+
-+static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
-+{
-+ return pipe->ep_num;
-+}
-+
-+static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return pipe->pipe_type;
-+}
-+
-+static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
-+{
-+ return pipe->mps;
-+}
-+
-+static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return pipe->dev_addr;
-+}
-+
-+static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return (pipe->pipe_type == UE_ISOCHRONOUS);
-+}
-+
-+static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return (pipe->pipe_type == UE_INTERRUPT);
-+}
-+
-+static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return (pipe->pipe_type == UE_BULK);
-+}
-+
-+static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return (pipe->pipe_type == UE_CONTROL);
-+}
-+
-+static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
-+{
-+ return (pipe->pipe_dir == UE_DIR_IN);
-+}
-+
-+static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
-+ *pipe)
-+{
-+ return (!dwc_otg_hcd_is_pipe_in(pipe));
-+}
-+
-+static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
-+ uint8_t devaddr, uint8_t ep_num,
-+ uint8_t pipe_type, uint8_t pipe_dir,
-+ uint16_t mps)
-+{
-+ pipe->dev_addr = devaddr;
-+ pipe->ep_num = ep_num;
-+ pipe->pipe_type = pipe_type;
-+ pipe->pipe_dir = pipe_dir;
-+ pipe->mps = mps;
-+}
-+
-+/**
-+ * Phases for control transfers.
-+ */
-+typedef enum dwc_otg_control_phase {
-+ DWC_OTG_CONTROL_SETUP,
-+ DWC_OTG_CONTROL_DATA,
-+ DWC_OTG_CONTROL_STATUS
-+} dwc_otg_control_phase_e;
-+
-+/** Transaction types. */
-+typedef enum dwc_otg_transaction_type {
-+ DWC_OTG_TRANSACTION_NONE = 0,
-+ DWC_OTG_TRANSACTION_PERIODIC = 1,
-+ DWC_OTG_TRANSACTION_NON_PERIODIC = 2,
-+ DWC_OTG_TRANSACTION_ALL = DWC_OTG_TRANSACTION_PERIODIC + DWC_OTG_TRANSACTION_NON_PERIODIC
-+} dwc_otg_transaction_type_e;
-+
-+struct dwc_otg_qh;
-+
-+/**
-+ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
-+ * interrupt, or isochronous transfer. A single QTD is created for each URB
-+ * (of one of these types) submitted to the HCD. The transfer associated with
-+ * a QTD may require one or multiple transactions.
-+ *
-+ * A QTD is linked to a Queue Head, which is entered in either the
-+ * non-periodic or periodic schedule for execution. When a QTD is chosen for
-+ * execution, some or all of its transactions may be executed. After
-+ * execution, the state of the QTD is updated. The QTD may be retired if all
-+ * its transactions are complete or if an error occurred. Otherwise, it
-+ * remains in the schedule so more transactions can be executed later.
-+ */
-+typedef struct dwc_otg_qtd {
-+ /**
-+ * Determines the PID of the next data packet for the data phase of
-+ * control transfers. Ignored for other transfer types.<br>
-+ * One of the following values:
-+ * - DWC_OTG_HC_PID_DATA0
-+ * - DWC_OTG_HC_PID_DATA1
-+ */
-+ uint8_t data_toggle;
-+
-+ /** Current phase for control transfers (Setup, Data, or Status). */
-+ dwc_otg_control_phase_e control_phase;
-+
-+ /** Keep track of the current split type
-+ * for FS/LS endpoints on a HS Hub */
-+ uint8_t complete_split;
-+
-+ /** How many bytes transferred during SSPLIT OUT */
-+ uint32_t ssplit_out_xfer_count;
-+
-+ /**
-+ * Holds the number of bus errors that have occurred for a transaction
-+ * within this transfer.
-+ */
-+ uint8_t error_count;
-+
-+ /**
-+ * Index of the next frame descriptor for an isochronous transfer. A
-+ * frame descriptor describes the buffer position and length of the
-+ * data to be transferred in the next scheduled (micro)frame of an
-+ * isochronous transfer. It also holds status for that transaction.
-+ * The frame index starts at 0.
-+ */
-+ uint16_t isoc_frame_index;
-+
-+ /** Position of the ISOC split on full/low speed */
-+ uint8_t isoc_split_pos;
-+
-+ /** Position of the ISOC split in the buffer for the current frame */
-+ uint16_t isoc_split_offset;
-+
-+ /** URB for this transfer */
-+ struct dwc_otg_hcd_urb *urb;
-+
-+ struct dwc_otg_qh *qh;
-+
-+ /** This list of QTDs */
-+ DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
-+
-+ /** Indicates if this QTD is currently processed by HW. */
-+ uint8_t in_process;
-+
-+ /** Number of DMA descriptors for this QTD */
-+ uint8_t n_desc;
-+
-+ /**
-+ * Last activated frame(packet) index.
-+ * Used in Descriptor DMA mode only.
-+ */
-+ uint16_t isoc_frame_index_last;
-+
-+} dwc_otg_qtd_t;
-+
-+DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
-+
-+/**
-+ * A Queue Head (QH) holds the static characteristics of an endpoint and
-+ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
-+ * be entered in either the non-periodic or periodic schedule.
-+ */
-+typedef struct dwc_otg_qh {
-+ /**
-+ * Endpoint type.
-+ * One of the following values:
-+ * - UE_CONTROL
-+ * - UE_BULK
-+ * - UE_INTERRUPT
-+ * - UE_ISOCHRONOUS
-+ */
-+ uint8_t ep_type;
-+ uint8_t ep_is_in;
-+
-+ /** wMaxPacketSize Field of Endpoint Descriptor. */
-+ uint16_t maxp;
-+
-+ /**
-+ * Device speed.
-+ * One of the following values:
-+ * - DWC_OTG_EP_SPEED_LOW
-+ * - DWC_OTG_EP_SPEED_FULL
-+ * - DWC_OTG_EP_SPEED_HIGH
-+ */
-+ uint8_t dev_speed;
-+
-+ /**
-+ * Determines the PID of the next data packet for non-control
-+ * transfers. Ignored for control transfers.<br>
-+ * One of the following values:
-+ * - DWC_OTG_HC_PID_DATA0
-+ * - DWC_OTG_HC_PID_DATA1
-+ */
-+ uint8_t data_toggle;
-+
-+ /** Ping state if 1. */
-+ uint8_t ping_state;
-+
-+ /**
-+ * List of QTDs for this QH.
-+ */
-+ struct dwc_otg_qtd_list qtd_list;
-+
-+ /** Host channel currently processing transfers for this QH. */
-+ struct dwc_hc *channel;
-+
-+ /** Full/low speed endpoint on high-speed hub requires split. */
-+ uint8_t do_split;
-+
-+ /** @name Periodic schedule information */
-+ /** @{ */
-+
-+ /** Bandwidth in microseconds per (micro)frame. */
-+ uint16_t usecs;
-+
-+ /** Interval between transfers in (micro)frames. */
-+ uint16_t interval;
-+
-+ /**
-+ * (micro)frame to initialize a periodic transfer. The transfer
-+ * executes in the following (micro)frame.
-+ */
-+ uint16_t sched_frame;
-+
-+ /*
-+ ** Frame a NAK was received on this queue head, used to minimise NAK retransmission
-+ */
-+ uint16_t nak_frame;
-+
-+ /** (micro)frame at which last start split was initialized. */
-+ uint16_t start_split_frame;
-+
-+ /** @} */
-+
-+ /**
-+ * Used instead of original buffer if
-+ * it(physical address) is not dword-aligned.
-+ */
-+ uint8_t *dw_align_buf;
-+ dwc_dma_t dw_align_buf_dma;
-+
-+ /** Entry for QH in either the periodic or non-periodic schedule. */
-+ dwc_list_link_t qh_list_entry;
-+
-+ /** @name Descriptor DMA support */
-+ /** @{ */
-+
-+ /** Descriptor List. */
-+ dwc_otg_host_dma_desc_t *desc_list;
-+
-+ /** Descriptor List physical address. */
-+ dwc_dma_t desc_list_dma;
-+
-+ /**
-+ * Xfer Bytes array.
-+ * Each element corresponds to a descriptor and indicates
-+ * original XferSize size value for the descriptor.
-+ */
-+ uint32_t *n_bytes;
-+
-+ /** Actual number of transfer descriptors in a list. */
-+ uint16_t ntd;
-+
-+ /** First activated isochronous transfer descriptor index. */
-+ uint8_t td_first;
-+ /** Last activated isochronous transfer descriptor index. */
-+ uint8_t td_last;
-+
-+ /** @} */
-+
-+
-+ uint16_t speed;
-+ uint16_t frame_usecs[8];
-+
-+ uint32_t skip_count;
-+} dwc_otg_qh_t;
-+
-+DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
-+
-+typedef struct urb_tq_entry {
-+ struct urb *urb;
-+ DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries;
-+} urb_tq_entry_t;
-+
-+DWC_TAILQ_HEAD(urb_list, urb_tq_entry);
-+
-+/**
-+ * This structure holds the state of the HCD, including the non-periodic and
-+ * periodic schedules.
-+ */
-+struct dwc_otg_hcd {
-+ /** The DWC otg device pointer */
-+ struct dwc_otg_device *otg_dev;
-+ /** DWC OTG Core Interface Layer */
-+ dwc_otg_core_if_t *core_if;
-+
-+ /** Function HCD driver callbacks */
-+ struct dwc_otg_hcd_function_ops *fops;
-+
-+ /** Internal DWC HCD Flags */
-+ volatile union dwc_otg_hcd_internal_flags {
-+ uint32_t d32;
-+ struct {
-+ unsigned port_connect_status_change:1;
-+ unsigned port_connect_status:1;
-+ unsigned port_reset_change:1;
-+ unsigned port_enable_change:1;
-+ unsigned port_suspend_change:1;
-+ unsigned port_over_current_change:1;
-+ unsigned port_l1_change:1;
-+ unsigned reserved:26;
-+ } b;
-+ } flags;
-+
-+ /**
-+ * Inactive items in the non-periodic schedule. This is a list of
-+ * Queue Heads. Transfers associated with these Queue Heads are not
-+ * currently assigned to a host channel.
-+ */
-+ dwc_list_link_t non_periodic_sched_inactive;
-+
-+ /**
-+ * Active items in the non-periodic schedule. This is a list of
-+ * Queue Heads. Transfers associated with these Queue Heads are
-+ * currently assigned to a host channel.
-+ */
-+ dwc_list_link_t non_periodic_sched_active;
-+
-+ /**
-+ * Pointer to the next Queue Head to process in the active
-+ * non-periodic schedule.
-+ */
-+ dwc_list_link_t *non_periodic_qh_ptr;
-+
-+ /**
-+ * Inactive items in the periodic schedule. This is a list of QHs for
-+ * periodic transfers that are _not_ scheduled for the next frame.
-+ * Each QH in the list has an interval counter that determines when it
-+ * needs to be scheduled for execution. This scheduling mechanism
-+ * allows only a simple calculation for periodic bandwidth used (i.e.
-+ * must assume that all periodic transfers may need to execute in the
-+ * same frame). However, it greatly simplifies scheduling and should
-+ * be sufficient for the vast majority of OTG hosts, which need to
-+ * connect to a small number of peripherals at one time.
-+ *
-+ * Items move from this list to periodic_sched_ready when the QH
-+ * interval counter is 0 at SOF.
-+ */
-+ dwc_list_link_t periodic_sched_inactive;
-+
-+ /**
-+ * List of periodic QHs that are ready for execution in the next
-+ * frame, but have not yet been assigned to host channels.
-+ *
-+ * Items move from this list to periodic_sched_assigned as host
-+ * channels become available during the current frame.
-+ */
-+ dwc_list_link_t periodic_sched_ready;
-+
-+ /**
-+ * List of periodic QHs to be executed in the next frame that are
-+ * assigned to host channels.
-+ *
-+ * Items move from this list to periodic_sched_queued as the
-+ * transactions for the QH are queued to the DWC_otg controller.
-+ */
-+ dwc_list_link_t periodic_sched_assigned;
-+
-+ /**
-+ * List of periodic QHs that have been queued for execution.
-+ *
-+ * Items move from this list to either periodic_sched_inactive or
-+ * periodic_sched_ready when the channel associated with the transfer
-+ * is released. If the interval for the QH is 1, the item moves to
-+ * periodic_sched_ready because it must be rescheduled for the next
-+ * frame. Otherwise, the item moves to periodic_sched_inactive.
-+ */
-+ dwc_list_link_t periodic_sched_queued;
-+
-+ /**
-+ * Total bandwidth claimed so far for periodic transfers. This value
-+ * is in microseconds per (micro)frame. The assumption is that all
-+ * periodic transfers may occur in the same (micro)frame.
-+ */
-+ uint16_t periodic_usecs;
-+
-+ /**
-+ * Total bandwidth claimed so far for all periodic transfers
-+ * in a frame.
-+ * This will include a mixture of HS and FS transfers.
-+ * Units are microseconds per (micro)frame.
-+ * We have a budget per frame and have to schedule
-+ * transactions accordingly.
-+ * Watch out for the fact that things are actually scheduled for the
-+ * "next frame".
-+ */
-+ uint16_t frame_usecs[8];
-+
-+
-+ /**
-+ * Frame number read from the core at SOF. The value ranges from 0 to
-+ * DWC_HFNUM_MAX_FRNUM.
-+ */
-+ uint16_t frame_number;
-+
-+ /**
-+ * Count of periodic QHs, if using several eps. For SOF enable/disable.
-+ */
-+ uint16_t periodic_qh_count;
-+
-+ /**
-+ * Free host channels in the controller. This is a list of
-+ * dwc_hc_t items.
-+ */
-+ struct hc_list free_hc_list;
-+ /**
-+ * Number of host channels assigned to periodic transfers. Currently
-+ * assuming that there is a dedicated host channel for each periodic
-+ * transaction and at least one host channel available for
-+ * non-periodic transactions.
-+ */
-+ int periodic_channels; /* microframe_schedule==0 */
-+
-+ /**
-+ * Number of host channels assigned to non-periodic transfers.
-+ */
-+ int non_periodic_channels; /* microframe_schedule==0 */
-+
-+ /**
-+ * Number of host channels assigned to non-periodic transfers.
-+ */
-+ int available_host_channels;
-+
-+ /**
-+ * Array of pointers to the host channel descriptors. Allows accessing
-+ * a host channel descriptor given the host channel number. This is
-+ * useful in interrupt handlers.
-+ */
-+ struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
-+
-+ /**
-+ * Buffer to use for any data received during the status phase of a
-+ * control transfer. Normally no data is transferred during the status
-+ * phase. This buffer is used as a bit bucket.
-+ */
-+ uint8_t *status_buf;
-+
-+ /**
-+ * DMA address for status_buf.
-+ */
-+ dma_addr_t status_buf_dma;
-+#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
-+
-+ /**
-+ * Connection timer. An OTG host must display a message if the device
-+ * does not connect. Started when the VBus power is turned on via
-+ * sysfs attribute "buspower".
-+ */
-+ dwc_timer_t *conn_timer;
-+
-+ /* Tasket to do a reset */
-+ dwc_tasklet_t *reset_tasklet;
-+
-+ dwc_tasklet_t *completion_tasklet;
-+ struct urb_list completed_urb_list;
-+
-+ /* */
-+ dwc_spinlock_t *lock;
-+ dwc_spinlock_t *channel_lock;
-+ /**
-+ * Private data that could be used by OS wrapper.
-+ */
-+ void *priv;
-+
-+ uint8_t otg_port;
-+
-+ /** Frame List */
-+ uint32_t *frame_list;
-+
-+ /** Hub - Port assignment */
-+ int hub_port[128];
-+#ifdef FIQ_DEBUG
-+ int hub_port_alloc[2048];
-+#endif
-+
-+ /** Frame List DMA address */
-+ dma_addr_t frame_list_dma;
-+
-+#ifdef DEBUG
-+ uint32_t frrem_samples;
-+ uint64_t frrem_accum;
-+
-+ uint32_t hfnum_7_samples_a;
-+ uint64_t hfnum_7_frrem_accum_a;
-+ uint32_t hfnum_0_samples_a;
-+ uint64_t hfnum_0_frrem_accum_a;
-+ uint32_t hfnum_other_samples_a;
-+ uint64_t hfnum_other_frrem_accum_a;
-+
-+ uint32_t hfnum_7_samples_b;
-+ uint64_t hfnum_7_frrem_accum_b;
-+ uint32_t hfnum_0_samples_b;
-+ uint64_t hfnum_0_frrem_accum_b;
-+ uint32_t hfnum_other_samples_b;
-+ uint64_t hfnum_other_frrem_accum_b;
-+#endif
-+};
-+
-+/** @name Transaction Execution Functions */
-+/** @{ */
-+extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
-+ * hcd);
-+extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
-+ dwc_otg_transaction_type_e tr_type);
-+
-+int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh);
-+void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh);
-+
-+
-+/** @} */
-+
-+/** @name Interrupt Handler Functions */
-+/** @{ */
-+extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
-+ dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
-+ dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
-+ dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
-+ dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
-+ dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
-+ uint32_t num);
-+extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
-+ dwc_otg_hcd);
-+/** @} */
-+
-+/** @name Schedule Queue Functions */
-+/** @{ */
-+
-+/* Implemented in dwc_otg_hcd_queue.c */
-+extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
-+ dwc_otg_hcd_urb_t * urb, int atomic_alloc);
-+extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
-+extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
-+extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
-+extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
-+ int sched_csplit);
-+
-+/** Remove and free a QH */
-+static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
-+ dwc_otg_qh_t * qh)
-+{
-+ dwc_irqflags_t flags;
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ dwc_otg_hcd_qh_free(hcd, qh);
-+}
-+
-+/** Allocates memory for a QH structure.
-+ * @return Returns the memory allocate or NULL on error. */
-+static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc)
-+{
-+ if (atomic_alloc)
-+ return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t));
-+ else
-+ return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t));
-+}
-+
-+extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb,
-+ int atomic_alloc);
-+extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
-+extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
-+ dwc_otg_qh_t ** qh, int atomic_alloc);
-+
-+/** Allocates memory for a QTD structure.
-+ * @return Returns the memory allocate or NULL on error. */
-+static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc)
-+{
-+ if (atomic_alloc)
-+ return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t));
-+ else
-+ return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t));
-+}
-+
-+/** Frees the memory for a QTD structure. QTD should already be removed from
-+ * list.
-+ * @param qtd QTD to free.*/
-+static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
-+{
-+ DWC_FREE(qtd);
-+}
-+
-+/** Removes a QTD from list.
-+ * @param hcd HCD instance.
-+ * @param qtd QTD to remove from list.
-+ * @param qh QTD belongs to.
-+ */
-+static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_qh_t * qh)
-+{
-+ DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
-+}
-+
-+/** Remove and free a QTD
-+ * Need to disable IRQ and hold hcd lock while calling this function out of
-+ * interrupt servicing chain */
-+static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_qh_t * qh)
-+{
-+ dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
-+ dwc_otg_hcd_qtd_free(qtd);
-+}
-+
-+/** @} */
-+
-+/** @name Descriptor DMA Supporting Functions */
-+/** @{ */
-+
-+extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
-+extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_halt_status_e halt_status);
-+
-+extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
-+extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
-+
-+/** @} */
-+
-+/** @name Internal Functions */
-+/** @{ */
-+dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
-+/** @} */
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
-+ uint8_t devaddr);
-+extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
-+#endif
-+
-+/** Gets the QH that contains the list_head */
-+#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
-+
-+/** Gets the QTD that contains the list_head */
-+#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
-+
-+/** Check if QH is non-periodic */
-+#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
-+ (_qh_ptr_->ep_type == UE_CONTROL))
-+
-+/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
-+#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-+
-+/** Packet size for any kind of endpoint descriptor */
-+#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
-+
-+/**
-+ * Returns true if _frame1 is less than or equal to _frame2. The comparison is
-+ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
-+ * frame number when the max frame number is reached.
-+ */
-+static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
-+{
-+ return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
-+ (DWC_HFNUM_MAX_FRNUM >> 1);
-+}
-+
-+/**
-+ * Returns true if _frame1 is greater than _frame2. The comparison is done
-+ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
-+ * number when the max frame number is reached.
-+ */
-+static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
-+{
-+ return (frame1 != frame2) &&
-+ (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
-+ (DWC_HFNUM_MAX_FRNUM >> 1));
-+}
-+
-+/**
-+ * Increments _frame by the amount specified by _inc. The addition is done
-+ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
-+ */
-+static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
-+{
-+ return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
-+}
-+
-+static inline uint16_t dwc_full_frame_num(uint16_t frame)
-+{
-+ return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
-+}
-+
-+static inline uint16_t dwc_micro_frame_num(uint16_t frame)
-+{
-+ return frame & 0x7;
-+}
-+
-+void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd);
-+
-+#ifdef DEBUG
-+/**
-+ * Macro to sample the remaining PHY clocks left in the current frame. This
-+ * may be used during debugging to determine the average time it takes to
-+ * execute sections of code. There are two possible sample points, "a" and
-+ * "b", so the _letter argument must be one of these values.
-+ *
-+ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
-+ * example, "cat /sys/devices/lm0/hcd_frrem".
-+ */
-+#define dwc_sample_frrem(_hcd, _qh, _letter) \
-+{ \
-+ hfnum_data_t hfnum; \
-+ dwc_otg_qtd_t *qtd; \
-+ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
-+ if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
-+ hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
-+ switch (hfnum.b.frnum & 0x7) { \
-+ case 7: \
-+ _hcd->hfnum_7_samples_##_letter++; \
-+ _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
-+ break; \
-+ case 0: \
-+ _hcd->hfnum_0_samples_##_letter++; \
-+ _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
-+ break; \
-+ default: \
-+ _hcd->hfnum_other_samples_##_letter++; \
-+ _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
-+ break; \
-+ } \
-+ } \
-+}
-+#else
-+#define dwc_sample_frrem(_hcd, _qh, _letter)
-+#endif
-+#endif
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,417 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
-+ * $Revision: #12 $
-+ * $Date: 2011/10/26 $
-+ * $Change: 1873028 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+#ifndef __DWC_HCD_IF_H__
-+#define __DWC_HCD_IF_H__
-+
-+#include "dwc_otg_core_if.h"
-+
-+/** @file
-+ * This file defines DWC_OTG HCD Core API.
-+ */
-+
-+struct dwc_otg_hcd;
-+typedef struct dwc_otg_hcd dwc_otg_hcd_t;
-+
-+struct dwc_otg_hcd_urb;
-+typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
-+
-+/** @name HCD Function Driver Callbacks */
-+/** @{ */
-+
-+/** This function is called whenever core switches to host mode. */
-+typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
-+
-+/** This function is called when device has been disconnected */
-+typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
-+
-+/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */
-+typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
-+ void *urb_handle,
-+ uint32_t * hub_addr,
-+ uint32_t * port_addr);
-+/** Via this function HCD core gets device speed */
-+typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
-+ void *urb_handle);
-+
-+/** This function is called when urb is completed */
-+typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
-+ void *urb_handle,
-+ dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ int32_t status);
-+
-+/** Via this function HCD core gets b_hnp_enable parameter */
-+typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
-+
-+struct dwc_otg_hcd_function_ops {
-+ dwc_otg_hcd_start_cb_t start;
-+ dwc_otg_hcd_disconnect_cb_t disconnect;
-+ dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
-+ dwc_otg_hcd_speed_from_urb_cb_t speed;
-+ dwc_otg_hcd_complete_urb_cb_t complete;
-+ dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
-+};
-+/** @} */
-+
-+/** @name HCD Core API */
-+/** @{ */
-+/** This function allocates dwc_otg_hcd structure and returns pointer on it. */
-+extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
-+
-+/** This function should be called to initiate HCD Core.
-+ *
-+ * @param hcd The HCD
-+ * @param core_if The DWC_OTG Core
-+ *
-+ * Returns -DWC_E_NO_MEMORY if no enough memory.
-+ * Returns 0 on success
-+ */
-+extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
-+
-+/** Frees HCD
-+ *
-+ * @param hcd The HCD
-+ */
-+extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
-+
-+/** This function should be called on every hardware interrupt.
-+ *
-+ * @param dwc_otg_hcd The HCD
-+ *
-+ * Returns non zero if interrupt is handled
-+ * Return 0 if interrupt is not handled
-+ */
-+extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-+
-+/** This function is used to handle the fast interrupt
-+ *
-+ */
-+extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void);
-+
-+/**
-+ * Returns private data set by
-+ * dwc_otg_hcd_set_priv_data function.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Set private data.
-+ *
-+ * @param hcd The HCD
-+ * @param priv_data pointer to be stored in private data
-+ */
-+extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
-+
-+/**
-+ * This function initializes the HCD Core.
-+ *
-+ * @param hcd The HCD
-+ * @param fops The Function Driver Operations data structure containing pointers to all callbacks.
-+ *
-+ * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode.
-+ * Returns 0 on success
-+ */
-+extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
-+ struct dwc_otg_hcd_function_ops *fops);
-+
-+/**
-+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
-+ * stopped.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Handles hub class-specific requests.
-+ *
-+ * @param dwc_otg_hcd The HCD
-+ * @param typeReq Request Type
-+ * @param wValue wValue from control request
-+ * @param wIndex wIndex from control request
-+ * @param buf data buffer
-+ * @param wLength data buffer length
-+ *
-+ * Returns -DWC_E_INVALID if invalid argument is passed
-+ * Returns 0 on success
-+ */
-+extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
-+ uint16_t typeReq, uint16_t wValue,
-+ uint16_t wIndex, uint8_t * buf,
-+ uint16_t wLength);
-+
-+/**
-+ * Returns otg port number.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Returns OTG version - either 1.3 or 2.0.
-+ *
-+ * @param core_if The core_if structure pointer
-+ */
-+extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if);
-+
-+/**
-+ * Returns 1 if currently core is acting as B host, and 0 otherwise.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Returns current frame number.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Dumps hcd state.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Dump the average frame remaining at SOF. This can be used to
-+ * determine average interrupt latency. Frame remaining is also shown for
-+ * start transfer and two additional sample points.
-+ * Currently this function is not implemented.
-+ *
-+ * @param hcd The HCD
-+ */
-+extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
-+
-+/**
-+ * Sends LPM transaction to the local device.
-+ *
-+ * @param hcd The HCD
-+ * @param devaddr Device Address
-+ * @param hird Host initiated resume duration
-+ * @param bRemoteWake Value of bRemoteWake field in LPM transaction
-+ *
-+ * Returns negative value if sending LPM transaction was not succeeded.
-+ * Returns 0 on success.
-+ */
-+extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
-+ uint8_t hird, uint8_t bRemoteWake);
-+
-+/* URB interface */
-+
-+/**
-+ * Allocates memory for dwc_otg_hcd_urb structure.
-+ * Allocated memory should be freed by call of DWC_FREE.
-+ *
-+ * @param hcd The HCD
-+ * @param iso_desc_count Count of ISOC descriptors
-+ * @param atomic_alloc Specefies whether to perform atomic allocation.
-+ */
-+extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
-+ int iso_desc_count,
-+ int atomic_alloc);
-+
-+/**
-+ * Set pipe information in URB.
-+ *
-+ * @param hcd_urb DWC_OTG URB
-+ * @param devaddr Device Address
-+ * @param ep_num Endpoint Number
-+ * @param ep_type Endpoint Type
-+ * @param ep_dir Endpoint Direction
-+ * @param mps Max Packet Size
-+ */
-+extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
-+ uint8_t devaddr, uint8_t ep_num,
-+ uint8_t ep_type, uint8_t ep_dir,
-+ uint16_t mps);
-+
-+/* Transfer flags */
-+#define URB_GIVEBACK_ASAP 0x1
-+#define URB_SEND_ZERO_PACKET 0x2
-+
-+/**
-+ * Sets dwc_otg_hcd_urb parameters.
-+ *
-+ * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
-+ * @param urb_handle Unique handle for request, this will be passed back
-+ * to function driver in completion callback.
-+ * @param buf The buffer for the data
-+ * @param dma The DMA buffer for the data
-+ * @param buflen Transfer length
-+ * @param sp Buffer for setup data
-+ * @param sp_dma DMA address of setup data buffer
-+ * @param flags Transfer flags
-+ * @param interval Polling interval for interrupt or isochronous transfers.
-+ */
-+extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
-+ void *urb_handle, void *buf,
-+ dwc_dma_t dma, uint32_t buflen, void *sp,
-+ dwc_dma_t sp_dma, uint32_t flags,
-+ uint16_t interval);
-+
-+/** Gets status from dwc_otg_hcd_urb
-+ *
-+ * @param dwc_otg_urb DWC_OTG URB
-+ */
-+extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
-+
-+/** Gets actual length from dwc_otg_hcd_urb
-+ *
-+ * @param dwc_otg_urb DWC_OTG URB
-+ */
-+extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
-+ dwc_otg_urb);
-+
-+/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs
-+ *
-+ * @param dwc_otg_urb DWC_OTG URB
-+ */
-+extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
-+ dwc_otg_urb);
-+
-+/** Set ISOC descriptor offset and length
-+ *
-+ * @param dwc_otg_urb DWC_OTG URB
-+ * @param desc_num ISOC descriptor number
-+ * @param offset Offset from beginig of buffer.
-+ * @param length Transaction length
-+ */
-+extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ int desc_num, uint32_t offset,
-+ uint32_t length);
-+
-+/** Get status of ISOC descriptor, specified by desc_num
-+ *
-+ * @param dwc_otg_urb DWC_OTG URB
-+ * @param desc_num ISOC descriptor number
-+ */
-+extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
-+ dwc_otg_urb, int desc_num);
-+
-+/** Get actual length of ISOC descriptor, specified by desc_num
-+ *
-+ * @param dwc_otg_urb DWC_OTG URB
-+ * @param desc_num ISOC descriptor number
-+ */
-+extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
-+ dwc_otg_urb,
-+ int desc_num);
-+
-+/** Queue URB. After transfer is completes, the complete callback will be called with the URB status
-+ *
-+ * @param dwc_otg_hcd The HCD
-+ * @param dwc_otg_urb DWC_OTG URB
-+ * @param ep_handle Out parameter for returning endpoint handle
-+ * @param atomic_alloc Flag to do atomic allocation if needed
-+ *
-+ * Returns -DWC_E_NO_DEVICE if no device is connected.
-+ * Returns -DWC_E_NO_MEMORY if there is no enough memory.
-+ * Returns 0 on success.
-+ */
-+extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
-+ dwc_otg_hcd_urb_t * dwc_otg_urb,
-+ void **ep_handle, int atomic_alloc);
-+
-+/** De-queue the specified URB
-+ *
-+ * @param dwc_otg_hcd The HCD
-+ * @param dwc_otg_urb DWC_OTG URB
-+ */
-+extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
-+ dwc_otg_hcd_urb_t * dwc_otg_urb);
-+
-+/** Frees resources in the DWC_otg controller related to a given endpoint.
-+ * Any URBs for the endpoint must already be dequeued.
-+ *
-+ * @param hcd The HCD
-+ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
-+ * @param retry Number of retries if there are queued transfers.
-+ *
-+ * Returns -DWC_E_INVALID if invalid arguments are passed.
-+ * Returns 0 on success
-+ */
-+extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
-+ int retry);
-+
-+/* Resets the data toggle in qh structure. This function can be called from
-+ * usb_clear_halt routine.
-+ *
-+ * @param hcd The HCD
-+ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
-+ *
-+ * Returns -DWC_E_INVALID if invalid arguments are passed.
-+ * Returns 0 on success
-+ */
-+extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle);
-+
-+/** Returns 1 if status of specified port is changed and 0 otherwise.
-+ *
-+ * @param hcd The HCD
-+ * @param port Port number
-+ */
-+extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
-+
-+/** Call this function to check if bandwidth was allocated for specified endpoint.
-+ * Only for ISOC and INTERRUPT endpoints.
-+ *
-+ * @param hcd The HCD
-+ * @param ep_handle Endpoint handle
-+ */
-+extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
-+ void *ep_handle);
-+
-+/** Call this function to check if bandwidth was freed for specified endpoint.
-+ *
-+ * @param hcd The HCD
-+ * @param ep_handle Endpoint handle
-+ */
-+extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
-+
-+/** Returns bandwidth allocated for specified endpoint in microseconds.
-+ * Only for ISOC and INTERRUPT endpoints.
-+ *
-+ * @param hcd The HCD
-+ * @param ep_handle Endpoint handle
-+ */
-+extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
-+ void *ep_handle);
-+
-+/** @} */
-+
-+#endif /* __DWC_HCD_IF_H__ */
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,2741 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
-+ * $Revision: #89 $
-+ * $Date: 2011/10/20 $
-+ * $Change: 1869487 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+
-+#include "dwc_otg_hcd.h"
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_mphi_fix.h"
-+
-+#include <linux/jiffies.h>
-+#include <mach/hardware.h>
-+#include <asm/fiq.h>
-+
-+
-+extern bool microframe_schedule;
-+
-+/** @file
-+ * This file contains the implementation of the HCD Interrupt handlers.
-+ */
-+
-+/*
-+ * Some globals to communicate between the FIQ and INTERRUPT
-+ */
-+
-+void * dummy_send;
-+mphi_regs_t c_mphi_regs;
-+volatile void *dwc_regs_base;
-+int fiq_done, int_done;
-+
-+gintsts_data_t gintsts_saved = {.d32 = 0};
-+hcint_data_t hcint_saved[MAX_EPS_CHANNELS];
-+hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS];
-+int split_out_xfersize[MAX_EPS_CHANNELS];
-+haint_data_t haint_saved;
-+
-+int g_next_sched_frame, g_np_count, g_np_sent;
-+static int mphi_int_count = 0 ;
-+
-+hcchar_data_t nak_hcchar;
-+hctsiz_data_t nak_hctsiz;
-+hcsplt_data_t nak_hcsplt;
-+int nak_count;
-+
-+int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
-+int split_start_frame[MAX_EPS_CHANNELS];
-+int queued_port[MAX_EPS_CHANNELS];
-+
-+#ifdef FIQ_DEBUG
-+char buffer[1000*16];
-+int wptr;
-+void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...)
-+{
-+ FIQDBG_T dbg_lvl_req = FIQDBG_PORTHUB;
-+ va_list args;
-+ char text[17];
-+ hfnum_data_t hfnum = { .d32 = FIQ_READ(dwc_regs_base + 0x408) };
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ local_fiq_disable();
-+ if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR)
-+ {
-+ snprintf(text, 9, "%4d%d:%d ", hfnum.b.frnum/8, hfnum.b.frnum%8, 8 - hfnum.b.frrem/937);
-+ va_start(args, fmt);
-+ vsnprintf(text+8, 9, fmt, args);
-+ va_end(args);
-+
-+ memcpy(buffer + wptr, text, 16);
-+ wptr = (wptr + 16) % sizeof(buffer);
-+ }
-+ local_irq_restore(flags);
-+}
-+#endif
-+
-+void notrace fiq_queue_request(int channel, int odd_frame)
-+{
-+ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) };
-+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) };
-+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10) };
-+
-+ if(hcsplt.b.spltena == 0)
-+ {
-+ fiq_print(FIQDBG_ERR, "SPLTENA ");
-+ BUG();
-+ }
-+
-+ if(hcchar.b.epdir == 1)
-+ {
-+ fiq_print(FIQDBG_SCHED, "IN Ch %d", channel);
-+ }
-+ else
-+ {
-+ hctsiz.b.xfersize = 0;
-+ fiq_print(FIQDBG_SCHED, "OUT Ch %d", channel);
-+ }
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x10), hctsiz.d32);
-+
-+ hcsplt.b.compsplt = 1;
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x4), hcsplt.d32);
-+
-+ // Send the Split complete
-+ hcchar.b.chen = 1;
-+ hcchar.b.oddfrm = odd_frame ? 1 : 0;
-+
-+ // Post this for transmit on the next frame for periodic or this frame for non-periodic
-+ fiq_print(FIQDBG_SCHED, "SND_%s", odd_frame ? "ODD " : "EVEN");
-+
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x0), hcchar.d32);
-+}
-+
-+static int last_sof = -1;
-+
-+/*
-+** Function to handle the start of frame interrupt, choose whether we need to do anything and
-+** therefore trigger the main interrupt
-+**
-+** returns int != 0 - interrupt has been handled
-+*/
-+int diff;
-+
-+int notrace fiq_sof_handle(hfnum_data_t hfnum)
-+{
-+ int handled = 0;
-+ int i;
-+
-+ // Just check that once we're running we don't miss a SOF
-+ /*if(last_sof != -1 && (hfnum.b.frnum != ((last_sof + 1) & 0x3fff)))
-+ {
-+ fiq_print(FIQDBG_ERR, "LASTSOF ");
-+ fiq_print(FIQDBG_ERR, "%4d%d ", last_sof / 8, last_sof & 7);
-+ fiq_print(FIQDBG_ERR, "%4d%d ", hfnum.b.frnum / 8, hfnum.b.frnum & 7);
-+ BUG();
-+ }*/
-+
-+ // Only start remembering the last sof when the interrupt has been
-+ // enabled (we don't check the mask to come in here...)
-+ if(last_sof != -1 || FIQ_READ(dwc_regs_base + 0x18) & (1<<3))
-+ last_sof = hfnum.b.frnum;
-+
-+ for(i = 0; i < MAX_EPS_CHANNELS; i++)
-+ {
-+ if(complete_sched[i] != -1)
-+ {
-+ if(complete_sched[i] <= hfnum.b.frnum || (complete_sched[i] > 0x3f00 && hfnum.b.frnum < 0xf0))
-+ {
-+ fiq_queue_request(i, hfnum.b.frnum & 1);
-+ complete_sched[i] = -1;
-+ }
-+ }
-+
-+ if(complete_sched[i] != -1)
-+ {
-+ // This is because we've seen a split complete occur with no start...
-+ // most likely because missed the complete 0x3fff frames ago!
-+
-+ diff = (hfnum.b.frnum + 0x3fff - complete_sched[i]) & 0x3fff ;
-+ if(diff > 32 && diff < 0x3f00)
-+ {
-+ fiq_print(FIQDBG_ERR, "SPLTMISS");
-+ BUG();
-+ }
-+ }
-+ }
-+
-+ if(g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum))
-+ {
-+ /*
-+ * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet
-+ * g_next_sched_frame is the next frame we have periodic packets for
-+ *
-+ * if neither of these are required for this frame then just clear the interrupt
-+ */
-+ handled = 1;
-+
-+ }
-+
-+ return handled;
-+}
-+
-+int notrace port_id(hcsplt_data_t hcsplt)
-+{
-+ return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8);
-+}
-+
-+int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum)
-+{
-+ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) };
-+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) };
-+ hcint_data_t hcint = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x8) };
-+ hcintmsk_data_t hcintmsk = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0xc) };
-+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10)};
-+
-+ hcint_saved[channel].d32 |= hcint.d32;
-+ hcintmsk_saved[channel].d32 = hcintmsk.d32;
-+
-+ if(hcsplt.b.spltena)
-+ {
-+ fiq_print(FIQDBG_PORTHUB, "ph: %4x", port_id(hcsplt));
-+ if(hcint.b.chhltd)
-+ {
-+ fiq_print(FIQDBG_SCHED, "CH HLT %d", channel);
-+ fiq_print(FIQDBG_SCHED, "%08x", hcint_saved[channel]);
-+ }
-+ if(hcint.b.stall || hcint.b.xacterr || hcint.b.bblerr || hcint.b.frmovrun || hcint.b.datatglerr)
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_ERR, "CHAN ERR");
-+ }
-+ if(hcint.b.xfercomp)
-+ {
-+ // Clear the port allocation and transmit anything also on this port
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_SCHED, "XFERCOMP");
-+ }
-+ if(hcint.b.nak)
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_SCHED, "NAK");
-+ }
-+ if(hcint.b.ack && !hcsplt.b.compsplt)
-+ {
-+ int i;
-+
-+ // Do not complete isochronous out transactions
-+ if(hcchar.b.eptype == 1 && hcchar.b.epdir == 0)
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_SCHED, "ISOC_OUT");
-+ }
-+ else
-+ {
-+ // Make sure we check the port / hub combination that we sent this split on.
-+ // Do not queue a second request to the same port
-+ for(i = 0; i < MAX_EPS_CHANNELS; i++)
-+ {
-+ if(port_id(hcsplt) == queued_port[i])
-+ {
-+ fiq_print(FIQDBG_ERR, "PORTERR ");
-+ //BUG();
-+ }
-+ }
-+
-+ split_start_frame[channel] = (hfnum.b.frnum + 1) & ~7;
-+
-+ // Note, the size of an OUT is in the start split phase, not
-+ // the complete split
-+ split_out_xfersize[channel] = hctsiz.b.xfersize;
-+
-+ hcint_saved[channel].b.chhltd = 0;
-+ hcint_saved[channel].b.ack = 0;
-+
-+ queued_port[channel] = port_id(hcsplt);
-+
-+ if(hcchar.b.eptype & 1)
-+ {
-+ // Send the periodic complete in the same oddness frame as the ACK went...
-+ fiq_queue_request(channel, !(hfnum.b.frnum & 1));
-+ // complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1);
-+ }
-+ else
-+ {
-+ // Schedule the split complete to occur later
-+ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 2);
-+ fiq_print(FIQDBG_SCHED, "ACK%04d%d", complete_sched[channel]/8, complete_sched[channel]%8);
-+ }
-+ }
-+ }
-+ if(hcint.b.nyet)
-+ {
-+ fiq_print(FIQDBG_ERR, "NYETERR1");
-+ //BUG();
-+ // Can transmit a split complete up to uframe .0 of the next frame
-+ if(hfnum.b.frnum <= dwc_frame_num_inc(split_start_frame[channel], 8))
-+ {
-+ // Send it next frame
-+ if(hcchar.b.eptype & 1) // type 1 & 3 are interrupt & isoc
-+ {
-+ fiq_print(FIQDBG_SCHED, "NYT:SEND");
-+ fiq_queue_request(channel, !(hfnum.b.frnum & 1));
-+ }
-+ else
-+ {
-+ // Schedule non-periodic access for next frame (the odd-even bit doesn't effect NP)
-+ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1);
-+ fiq_print(FIQDBG_SCHED, "NYT%04d%d", complete_sched[channel]/8, complete_sched[channel]%8);
-+ }
-+ hcint_saved[channel].b.chhltd = 0;
-+ hcint_saved[channel].b.nyet = 0;
-+ }
-+ else
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_ERR, "NYETERR2");
-+ //BUG();
-+ }
-+ }
-+ }
-+ else
-+ {
-+ /*
-+ * If we have any of NAK, ACK, Datatlgerr active on a
-+ * non-split channel, the sole reason is to reset error
-+ * counts for a previously broken transaction. The FIQ
-+ * will thrash on NAK IN and ACK OUT in particular so
-+ * handle it "once" and allow the IRQ to do the rest.
-+ */
-+ hcint.d32 &= hcintmsk.d32;
-+ if(hcint.b.nak)
-+ {
-+ hcintmsk.b.nak = 0;
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32);
-+ }
-+ if (hcint.b.ack)
-+ {
-+ hcintmsk.b.ack = 0;
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32);
-+ }
-+ }
-+
-+ // Clear the interrupt, this will also clear the HAINT bit
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32);
-+ return hcint_saved[channel].d32 == 0;
-+}
-+
-+gintsts_data_t gintsts;
-+gintmsk_data_t gintmsk;
-+// triggered: The set of interrupts that were triggered
-+// handled: The set of interrupts that have been handled (no IRQ is
-+// required)
-+// keep: The set of interrupts we want to keep unmasked even though we
-+// want to trigger an IRQ to handle it (SOF and HCINTR)
-+gintsts_data_t triggered, handled, keep;
-+hfnum_data_t hfnum;
-+
-+void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void)
-+{
-+
-+ /* entry takes care to store registers we will be treading on here */
-+ asm __volatile__ (
-+ "mov ip, sp ;"
-+ /* stash FIQ and normal regs */
-+ "stmdb sp!, {r0-r12, lr};"
-+ /* !! THIS SETS THE FRAME, adjust to > sizeof locals */
-+ "sub fp, ip, #512 ;"
-+ );
-+
-+ // Cannot put local variables at the beginning of the function
-+ // because otherwise 'C' will play with the stack pointer. any locals
-+ // need to be inside the following block
-+ do
-+ {
-+ fiq_done++;
-+ gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14);
-+ gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18);
-+ hfnum.d32 = FIQ_READ(dwc_regs_base + 0x408);
-+ triggered.d32 = gintsts.d32 & gintmsk.d32;
-+ handled.d32 = 0;
-+ keep.d32 = 0;
-+ fiq_print(FIQDBG_INT, "FIQ ");
-+ fiq_print(FIQDBG_INT, "%08x", gintsts.d32);
-+ fiq_print(FIQDBG_INT, "%08x", gintmsk.d32);
-+ if(gintsts.d32)
-+ {
-+ // If port enabled
-+ if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5)
-+ {
-+ if(gintsts.b.sofintr)
-+ {
-+ if(fiq_sof_handle(hfnum))
-+ {
-+ handled.b.sofintr = 1; /* Handled in FIQ */
-+ }
-+ else
-+ {
-+ /* Keer interrupt unmasked */
-+ keep.b.sofintr = 1;
-+ }
-+ {
-+ // Need to make sure the read and clearing of the SOF interrupt is as close as possible to avoid the possibility of missing
-+ // a start of frame interrupt
-+ gintsts_data_t gintsts = { .b.sofintr = 1 };
-+ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32);
-+ }
-+ }
-+
-+ if(fiq_split_enable && gintsts.b.hcintr)
-+ {
-+ int i;
-+ haint_data_t haint;
-+ haintmsk_data_t haintmsk;
-+
-+ haint.d32 = FIQ_READ(dwc_regs_base + 0x414);
-+ haintmsk.d32 = FIQ_READ(dwc_regs_base + 0x418);
-+ haint.d32 &= haintmsk.d32;
-+ haint_saved.d32 |= haint.d32;
-+
-+ fiq_print(FIQDBG_INT, "hcintr");
-+ fiq_print(FIQDBG_INT, "%08x", FIQ_READ(dwc_regs_base + 0x414));
-+
-+ // Go through each channel that has an enabled interrupt
-+ for(i = 0; i < 16; i++)
-+ if((haint.d32 >> i) & 1)
-+ if(fiq_hcintr_handle(i, hfnum))
-+ haint_saved.d32 &= ~(1 << i); /* this was handled */
-+
-+ /* If we've handled all host channel interrupts then don't trigger the interrupt */
-+ if(haint_saved.d32 == 0)
-+ {
-+ handled.b.hcintr = 1;
-+ }
-+ else
-+ {
-+ /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */
-+ keep.b.hcintr = 1;
-+ }
-+
-+ {
-+ gintsts_data_t gintsts = { .b.hcintr = 1 };
-+
-+ // Always clear the channel interrupt
-+ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32);
-+ }
-+ }
-+ }
-+ else
-+ {
-+ last_sof = -1;
-+ }
-+ }
-+
-+ // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep
-+ gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32));
-+ // Save those that were triggered but not handled
-+ gintsts_saved.d32 |= triggered.d32 & ~handled.d32;
-+ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32);
-+
-+ // Clear and save any unhandled interrupts and trigger the interrupt
-+ if(gintsts_saved.d32)
-+ {
-+ /* To enable the MPHI interrupt (INT 32)
-+ */
-+ FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send);
-+ FIQ_WRITE( c_mphi_regs.outddb, (1 << 29));
-+
-+ mphi_int_count++;
-+ }
-+ }
-+ while(0);
-+
-+ mb();
-+
-+ /* exit back to normal mode restoring everything */
-+ asm __volatile__ (
-+ /* return FIQ regs back to pristine state
-+ * and get normal regs back
-+ */
-+ "ldmia sp!, {r0-r12, lr};"
-+
-+ /* return */
-+ "subs pc, lr, #4;"
-+ );
-+}
-+
-+/** This function handles interrupts for the HCD. */
-+int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ int retval = 0;
-+ static int last_time;
-+
-+ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
-+ gintsts_data_t gintsts;
-+ gintmsk_data_t gintmsk;
-+ hfnum_data_t hfnum;
-+
-+#ifdef DEBUG
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+
-+#endif
-+
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+
-+ /* Exit from ISR if core is hibernated */
-+ if (core_if->hibernation_suspend == 1) {
-+ goto exit_handler_routine;
-+ }
-+ DWC_SPINLOCK(dwc_otg_hcd->lock);
-+ /* Check if HOST Mode */
-+ if (dwc_otg_is_host_mode(core_if)) {
-+ local_fiq_disable();
-+ gintmsk.d32 |= gintsts_saved.d32;
-+ gintsts.d32 |= gintsts_saved.d32;
-+ gintsts_saved.d32 = 0;
-+ local_fiq_enable();
-+ if (!gintsts.d32) {
-+ goto exit_handler_routine;
-+ }
-+ gintsts.d32 &= gintmsk.d32;
-+
-+#ifdef DEBUG
-+ // We should be OK doing this because the common interrupts should already have been serviced
-+ /* Don't print debug message in the interrupt handler on SOF */
-+#ifndef DEBUG_SOF
-+ if (gintsts.d32 != DWC_SOF_INTR_MASK)
-+#endif
-+ DWC_DEBUGPL(DBG_HCDI, "\n");
-+#endif
-+
-+#ifdef DEBUG
-+#ifndef DEBUG_SOF
-+ if (gintsts.d32 != DWC_SOF_INTR_MASK)
-+#endif
-+ DWC_DEBUGPL(DBG_HCDI,
-+ "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
-+ gintsts.d32, core_if);
-+#endif
-+ hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum);
-+ if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum))
-+ {
-+ /* Note, we should never get here if the FIQ is doing it's job properly*/
-+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
-+ }
-+ else if (gintsts.b.sofintr) {
-+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
-+ }
-+
-+ if (gintsts.b.rxstsqlvl) {
-+ retval |=
-+ dwc_otg_hcd_handle_rx_status_q_level_intr
-+ (dwc_otg_hcd);
-+ }
-+ if (gintsts.b.nptxfempty) {
-+ retval |=
-+ dwc_otg_hcd_handle_np_tx_fifo_empty_intr
-+ (dwc_otg_hcd);
-+ }
-+ if (gintsts.b.i2cintr) {
-+ /** @todo Implement i2cintr handler. */
-+ }
-+ if (gintsts.b.portintr) {
-+
-+ gintmsk_data_t gintmsk = { .b.portintr = 1};
-+ retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
-+ }
-+ if (gintsts.b.hcintr) {
-+ retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
-+ }
-+ if (gintsts.b.ptxfempty) {
-+ retval |=
-+ dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
-+ (dwc_otg_hcd);
-+ }
-+#ifdef DEBUG
-+#ifndef DEBUG_SOF
-+ if (gintsts.d32 != DWC_SOF_INTR_MASK)
-+#endif
-+ {
-+ DWC_DEBUGPL(DBG_HCDI,
-+ "DWC OTG HCD Finished Servicing Interrupts\n");
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
-+ DWC_READ_REG32(&global_regs->gintsts));
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
-+ DWC_READ_REG32(&global_regs->gintmsk));
-+ }
-+#endif
-+
-+#ifdef DEBUG
-+#ifndef DEBUG_SOF
-+ if (gintsts.d32 != DWC_SOF_INTR_MASK)
-+#endif
-+ DWC_DEBUGPL(DBG_HCDI, "\n");
-+#endif
-+
-+ }
-+
-+exit_handler_routine:
-+
-+ if (fiq_fix_enable)
-+ {
-+ local_fiq_disable();
-+ // Make sure that we don't clear the interrupt if we've still got pending work to do
-+ if(gintsts_saved.d32 == 0)
-+ {
-+ /* Clear the MPHI interrupt */
-+ DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16));
-+ if (mphi_int_count >= 60)
-+ {
-+ DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16)));
-+ while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17)))
-+ ;
-+ DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31));
-+ mphi_int_count = 0;
-+ }
-+ int_done++;
-+ }
-+
-+ // Unmask handled interrupts
-+ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32);
-+ //DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1);
-+
-+ local_fiq_enable();
-+
-+ if((jiffies / HZ) > last_time)
-+ {
-+ /* Once a second output the fiq and irq numbers, useful for debug */
-+ last_time = jiffies / HZ;
-+ DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done);
-+ }
-+ }
-+
-+ DWC_SPINUNLOCK(dwc_otg_hcd->lock);
-+ return retval;
-+}
-+
-+#ifdef DWC_TRACK_MISSED_SOFS
-+
-+#warning Compiling code to track missed SOFs
-+#define FRAME_NUM_ARRAY_SIZE 1000
-+/**
-+ * This function is for debug only.
-+ */
-+static inline void track_missed_sofs(uint16_t curr_frame_number)
-+{
-+ static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
-+ static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
-+ static int frame_num_idx = 0;
-+ static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
-+ static int dumped_frame_num_array = 0;
-+
-+ if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
-+ if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
-+ curr_frame_number) {
-+ frame_num_array[frame_num_idx] = curr_frame_number;
-+ last_frame_num_array[frame_num_idx++] = last_frame_num;
-+ }
-+ } else if (!dumped_frame_num_array) {
-+ int i;
-+ DWC_PRINTF("Frame Last Frame\n");
-+ DWC_PRINTF("----- ----------\n");
-+ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
-+ DWC_PRINTF("0x%04x 0x%04x\n",
-+ frame_num_array[i], last_frame_num_array[i]);
-+ }
-+ dumped_frame_num_array = 1;
-+ }
-+ last_frame_num = curr_frame_number;
-+}
-+#endif
-+
-+/**
-+ * Handles the start-of-frame interrupt in host mode. Non-periodic
-+ * transactions may be queued to the DWC_otg controller for the current
-+ * (micro)frame. Periodic transactions may be queued to the controller for the
-+ * next (micro)frame.
-+ */
-+int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
-+{
-+ hfnum_data_t hfnum;
-+ dwc_list_link_t *qh_entry;
-+ dwc_otg_qh_t *qh;
-+ dwc_otg_transaction_type_e tr_type;
-+ int did_something = 0;
-+ int32_t next_sched_frame = -1;
-+
-+ hfnum.d32 =
-+ DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
-+
-+#ifdef DEBUG_SOF
-+ DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
-+#endif
-+ hcd->frame_number = hfnum.b.frnum;
-+
-+#ifdef DEBUG
-+ hcd->frrem_accum += hfnum.b.frrem;
-+ hcd->frrem_samples++;
-+#endif
-+
-+#ifdef DWC_TRACK_MISSED_SOFS
-+ track_missed_sofs(hcd->frame_number);
-+#endif
-+ /* Determine whether any periodic QHs should be executed. */
-+ qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
-+ while (qh_entry != &hcd->periodic_sched_inactive) {
-+ qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
-+ qh_entry = qh_entry->next;
-+ if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
-+
-+ /*
-+ * Move QH to the ready list to be executed next
-+ * (micro)frame.
-+ */
-+ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
-+ &qh->qh_list_entry);
-+
-+ did_something = 1;
-+ }
-+ else
-+ {
-+ if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame))
-+ {
-+ next_sched_frame = qh->sched_frame;
-+ }
-+ }
-+ }
-+
-+ g_next_sched_frame = next_sched_frame;
-+
-+ tr_type = dwc_otg_hcd_select_transactions(hcd);
-+ if (tr_type != DWC_OTG_TRANSACTION_NONE) {
-+ dwc_otg_hcd_queue_transactions(hcd, tr_type);
-+ did_something = 1;
-+ }
-+
-+ /* Clear interrupt */
-+ gintsts.b.sofintr = 1;
-+ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
-+ * least one packet in the Rx FIFO. The packets are moved from the FIFO to
-+ * memory if the DWC_otg controller is operating in Slave mode. */
-+int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ host_grxsts_data_t grxsts;
-+ dwc_hc_t *hc = NULL;
-+
-+ DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
-+
-+ grxsts.d32 =
-+ DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
-+
-+ hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
-+ if (!hc) {
-+ DWC_ERROR("Unable to get corresponding channel\n");
-+ return 0;
-+ }
-+
-+ /* Packet Status */
-+ DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
-+ DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
-+ DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
-+ hc->data_pid_start);
-+ DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
-+
-+ switch (grxsts.b.pktsts) {
-+ case DWC_GRXSTS_PKTSTS_IN:
-+ /* Read the data into the host buffer. */
-+ if (grxsts.b.bcnt > 0) {
-+ dwc_otg_read_packet(dwc_otg_hcd->core_if,
-+ hc->xfer_buff, grxsts.b.bcnt);
-+
-+ /* Update the HC fields for the next packet received. */
-+ hc->xfer_count += grxsts.b.bcnt;
-+ hc->xfer_buff += grxsts.b.bcnt;
-+ }
-+
-+ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
-+ case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
-+ case DWC_GRXSTS_PKTSTS_CH_HALTED:
-+ /* Handled in interrupt, just ignore data */
-+ break;
-+ default:
-+ DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
-+ grxsts.b.pktsts);
-+ break;
-+ }
-+
-+ return 1;
-+}
-+
-+/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
-+ * data packets may be written to the FIFO for OUT transfers. More requests
-+ * may be written to the non-periodic request queue for IN transfers. This
-+ * interrupt is enabled only in Slave mode. */
-+int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
-+ dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
-+ DWC_OTG_TRANSACTION_NON_PERIODIC);
-+ return 1;
-+}
-+
-+/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
-+ * packets may be written to the FIFO for OUT transfers. More requests may be
-+ * written to the periodic request queue for IN transfers. This interrupt is
-+ * enabled only in Slave mode. */
-+int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
-+ dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
-+ DWC_OTG_TRANSACTION_PERIODIC);
-+ return 1;
-+}
-+
-+/** There are multiple conditions that can cause a port interrupt. This function
-+ * determines which interrupt conditions have occurred and handles them
-+ * appropriately. */
-+int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ int retval = 0;
-+ hprt0_data_t hprt0;
-+ hprt0_data_t hprt0_modify;
-+
-+ hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
-+ hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
-+
-+ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
-+ * GINTSTS */
-+
-+ hprt0_modify.b.prtena = 0;
-+ hprt0_modify.b.prtconndet = 0;
-+ hprt0_modify.b.prtenchng = 0;
-+ hprt0_modify.b.prtovrcurrchng = 0;
-+
-+ /* Port Connect Detected
-+ * Set flag and clear if detected */
-+ if (dwc_otg_hcd->core_if->hibernation_suspend == 1) {
-+ // Dont modify port status if we are in hibernation state
-+ hprt0_modify.b.prtconndet = 1;
-+ hprt0_modify.b.prtenchng = 1;
-+ DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
-+ hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
-+ return retval;
-+ }
-+
-+ if (hprt0.b.prtconndet) {
-+ /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */
-+ if (dwc_otg_hcd->core_if->adp_enable &&
-+ dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) {
-+ DWC_PRINTF("PORT CONNECT DETECTED ----------------\n");
-+ DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer);
-+ dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
-+ /* TODO - check if this is required, as
-+ * host initialization was already performed
-+ * after initial ADP probing
-+ */
-+ /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0;
-+ dwc_otg_core_init(dwc_otg_hcd->core_if);
-+ dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if);
-+ cil_hcd_start(dwc_otg_hcd->core_if);*/
-+ } else {
-+
-+ DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
-+ "Port Connect Detected--\n", hprt0.d32);
-+ dwc_otg_hcd->flags.b.port_connect_status_change = 1;
-+ dwc_otg_hcd->flags.b.port_connect_status = 1;
-+ hprt0_modify.b.prtconndet = 1;
-+
-+ /* B-Device has connected, Delete the connection timer. */
-+ DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
-+ }
-+ /* The Hub driver asserts a reset when it sees port connect
-+ * status change flag */
-+ retval |= 1;
-+ }
-+
-+ /* Port Enable Changed
-+ * Clear if detected - Set internal flag if disabled */
-+ if (hprt0.b.prtenchng) {
-+ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
-+ "Port Enable Changed--\n", hprt0.d32);
-+ hprt0_modify.b.prtenchng = 1;
-+ if (hprt0.b.prtena == 1) {
-+ hfir_data_t hfir;
-+ int do_reset = 0;
-+ dwc_otg_core_params_t *params =
-+ dwc_otg_hcd->core_if->core_params;
-+ dwc_otg_core_global_regs_t *global_regs =
-+ dwc_otg_hcd->core_if->core_global_regs;
-+ dwc_otg_host_if_t *host_if =
-+ dwc_otg_hcd->core_if->host_if;
-+
-+ /* Every time when port enables calculate
-+ * HFIR.FrInterval
-+ */
-+ hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
-+ hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if);
-+ DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
-+
-+ /* Check if we need to adjust the PHY clock speed for
-+ * low power and adjust it */
-+ if (params->host_support_fs_ls_low_power) {
-+ gusbcfg_data_t usbcfg;
-+
-+ usbcfg.d32 =
-+ DWC_READ_REG32(&global_regs->gusbcfg);
-+
-+ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
-+ || hprt0.b.prtspd ==
-+ DWC_HPRT0_PRTSPD_FULL_SPEED) {
-+ /*
-+ * Low power
-+ */
-+ hcfg_data_t hcfg;
-+ if (usbcfg.b.phylpwrclksel == 0) {
-+ /* Set PHY low power clock select for FS/LS devices */
-+ usbcfg.b.phylpwrclksel = 1;
-+ DWC_WRITE_REG32
-+ (&global_regs->gusbcfg,
-+ usbcfg.d32);
-+ do_reset = 1;
-+ }
-+
-+ hcfg.d32 =
-+ DWC_READ_REG32
-+ (&host_if->host_global_regs->hcfg);
-+
-+ if (hprt0.b.prtspd ==
-+ DWC_HPRT0_PRTSPD_LOW_SPEED
-+ && params->host_ls_low_power_phy_clk
-+ ==
-+ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
-+ {
-+ /* 6 MHZ */
-+ DWC_DEBUGPL(DBG_CIL,
-+ "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
-+ if (hcfg.b.fslspclksel !=
-+ DWC_HCFG_6_MHZ) {
-+ hcfg.b.fslspclksel =
-+ DWC_HCFG_6_MHZ;
-+ DWC_WRITE_REG32
-+ (&host_if->host_global_regs->hcfg,
-+ hcfg.d32);
-+ do_reset = 1;
-+ }
-+ } else {
-+ /* 48 MHZ */
-+ DWC_DEBUGPL(DBG_CIL,
-+ "FS_PHY programming HCFG to 48 MHz ()\n");
-+ if (hcfg.b.fslspclksel !=
-+ DWC_HCFG_48_MHZ) {
-+ hcfg.b.fslspclksel =
-+ DWC_HCFG_48_MHZ;
-+ DWC_WRITE_REG32
-+ (&host_if->host_global_regs->hcfg,
-+ hcfg.d32);
-+ do_reset = 1;
-+ }
-+ }
-+ } else {
-+ /*
-+ * Not low power
-+ */
-+ if (usbcfg.b.phylpwrclksel == 1) {
-+ usbcfg.b.phylpwrclksel = 0;
-+ DWC_WRITE_REG32
-+ (&global_regs->gusbcfg,
-+ usbcfg.d32);
-+ do_reset = 1;
-+ }
-+ }
-+
-+ if (do_reset) {
-+ DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet);
-+ }
-+ }
-+
-+ if (!do_reset) {
-+ /* Port has been enabled set the reset change flag */
-+ dwc_otg_hcd->flags.b.port_reset_change = 1;
-+ }
-+ } else {
-+ dwc_otg_hcd->flags.b.port_enable_change = 1;
-+ }
-+ retval |= 1;
-+ }
-+
-+ /** Overcurrent Change Interrupt */
-+ if (hprt0.b.prtovrcurrchng) {
-+ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
-+ "Port Overcurrent Changed--\n", hprt0.d32);
-+ dwc_otg_hcd->flags.b.port_over_current_change = 1;
-+ hprt0_modify.b.prtovrcurrchng = 1;
-+ retval |= 1;
-+ }
-+
-+ /* Clear Port Interrupts */
-+ DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
-+
-+ return retval;
-+}
-+
-+/** This interrupt indicates that one or more host channels has a pending
-+ * interrupt. There are multiple conditions that can cause each host channel
-+ * interrupt. This function determines which conditions have occurred for each
-+ * host channel interrupt and handles them appropriately. */
-+int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ int i;
-+ int retval = 0;
-+ haint_data_t haint;
-+
-+ /* Clear appropriate bits in HCINTn to clear the interrupt bit in
-+ * GINTSTS */
-+
-+ haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
-+
-+ // Overwrite with saved interrupts from fiq handler
-+ if(fiq_split_enable)
-+ {
-+ local_fiq_disable();
-+ haint.d32 = haint_saved.d32;
-+ haint_saved.d32 = 0;
-+ local_fiq_enable();
-+ }
-+
-+ for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
-+ if (haint.b2.chint & (1 << i)) {
-+ retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
-+ }
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * Gets the actual length of a transfer after the transfer halts. _halt_status
-+ * holds the reason for the halt.
-+ *
-+ * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE,
-+ * *short_read is set to 1 upon return if less than the requested
-+ * number of bytes were transferred. Otherwise, *short_read is set to 0 upon
-+ * return. short_read may also be NULL on entry, in which case it remains
-+ * unchanged.
-+ */
-+static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_halt_status_e halt_status,
-+ int *short_read)
-+{
-+ hctsiz_data_t hctsiz;
-+ uint32_t length;
-+
-+ if (short_read != NULL) {
-+ *short_read = 0;
-+ }
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+
-+ if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
-+ if (hc->ep_is_in) {
-+ length = hc->xfer_len - hctsiz.b.xfersize;
-+ if (short_read != NULL) {
-+ *short_read = (hctsiz.b.xfersize != 0);
-+ }
-+ } else if (hc->qh->do_split) {
-+ if(fiq_split_enable)
-+ length = split_out_xfersize[hc->hc_num];
-+ else
-+ length = qtd->ssplit_out_xfer_count;
-+ } else {
-+ length = hc->xfer_len;
-+ }
-+ } else {
-+ /*
-+ * Must use the hctsiz.pktcnt field to determine how much data
-+ * has been transferred. This field reflects the number of
-+ * packets that have been transferred via the USB. This is
-+ * always an integral number of packets if the transfer was
-+ * halted before its normal completion. (Can't use the
-+ * hctsiz.xfersize field because that reflects the number of
-+ * bytes transferred via the AHB, not the USB).
-+ */
-+ length =
-+ (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
-+ }
-+
-+ return length;
-+}
-+
-+/**
-+ * Updates the state of the URB after a Transfer Complete interrupt on the
-+ * host channel. Updates the actual_length field of the URB based on the
-+ * number of bytes transferred via the host channel. Sets the URB status
-+ * if the data transfer is finished.
-+ *
-+ * @return 1 if the data transfer specified by the URB is completely finished,
-+ * 0 otherwise.
-+ */
-+static int update_urb_state_xfer_comp(dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_hcd_urb_t * urb,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ int xfer_done = 0;
-+ int short_read = 0;
-+
-+ int xfer_length;
-+
-+ xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,
-+ DWC_OTG_HC_XFER_COMPLETE,
-+ &short_read);
-+
-+ /* non DWORD-aligned buffer case handling. */
-+ if (hc->align_buff && xfer_length && hc->ep_is_in) {
-+ dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
-+ xfer_length);
-+ }
-+
-+ urb->actual_length += xfer_length;
-+
-+ if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
-+ (urb->flags & URB_SEND_ZERO_PACKET)
-+ && (urb->actual_length == urb->length)
-+ && !(urb->length % hc->max_packet)) {
-+ xfer_done = 0;
-+ } else if (short_read || urb->actual_length >= urb->length) {
-+ xfer_done = 1;
-+ urb->status = 0;
-+ }
-+
-+#ifdef DEBUG
-+ {
-+ hctsiz_data_t hctsiz;
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
-+ __func__, (hc->ep_is_in ? "IN" : "OUT"),
-+ hc->hc_num);
-+ DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len);
-+ DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n",
-+ hctsiz.b.xfersize);
-+ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
-+ urb->length);
-+ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
-+ urb->actual_length);
-+ DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
-+ short_read, xfer_done);
-+ }
-+#endif
-+
-+ return xfer_done;
-+}
-+
-+/*
-+ * Save the starting data toggle for the next transfer. The data toggle is
-+ * saved in the QH for non-control transfers and it's saved in the QTD for
-+ * control transfers.
-+ */
-+void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
-+{
-+ hctsiz_data_t hctsiz;
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+
-+ if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
-+ dwc_otg_qh_t *qh = hc->qh;
-+ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
-+ qh->data_toggle = DWC_OTG_HC_PID_DATA0;
-+ } else {
-+ qh->data_toggle = DWC_OTG_HC_PID_DATA1;
-+ }
-+ } else {
-+ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
-+ qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
-+ } else {
-+ qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
-+ }
-+ }
-+}
-+
-+/**
-+ * Updates the state of an Isochronous URB when the transfer is stopped for
-+ * any reason. The fields of the current entry in the frame descriptor array
-+ * are set based on the transfer state and the input _halt_status. Completes
-+ * the Isochronous URB if all the URB frames have been completed.
-+ *
-+ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
-+ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
-+ */
-+static dwc_otg_halt_status_e
-+update_isoc_urb_state(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
-+{
-+ dwc_otg_hcd_urb_t *urb = qtd->urb;
-+ dwc_otg_halt_status_e ret_val = halt_status;
-+ struct dwc_otg_hcd_iso_packet_desc *frame_desc;
-+
-+ frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
-+ switch (halt_status) {
-+ case DWC_OTG_HC_XFER_COMPLETE:
-+ frame_desc->status = 0;
-+ frame_desc->actual_length =
-+ get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
-+
-+ /* non DWORD-aligned buffer case handling. */
-+ if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
-+ dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
-+ hc->qh->dw_align_buf, frame_desc->actual_length);
-+ }
-+
-+ break;
-+ case DWC_OTG_HC_XFER_FRAME_OVERRUN:
-+ urb->error_count++;
-+ if (hc->ep_is_in) {
-+ frame_desc->status = -DWC_E_NO_STREAM_RES;
-+ } else {
-+ frame_desc->status = -DWC_E_COMMUNICATION;
-+ }
-+ frame_desc->actual_length = 0;
-+ break;
-+ case DWC_OTG_HC_XFER_BABBLE_ERR:
-+ urb->error_count++;
-+ frame_desc->status = -DWC_E_OVERFLOW;
-+ /* Don't need to update actual_length in this case. */
-+ break;
-+ case DWC_OTG_HC_XFER_XACT_ERR:
-+ urb->error_count++;
-+ frame_desc->status = -DWC_E_PROTOCOL;
-+ frame_desc->actual_length =
-+ get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
-+
-+ /* non DWORD-aligned buffer case handling. */
-+ if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
-+ dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset,
-+ hc->qh->dw_align_buf, frame_desc->actual_length);
-+ }
-+ /* Skip whole frame */
-+ if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) &&
-+ hc->ep_is_in && hcd->core_if->dma_enable) {
-+ qtd->complete_split = 0;
-+ qtd->isoc_split_offset = 0;
-+ }
-+
-+ break;
-+ default:
-+ DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
-+ break;
-+ }
-+ if (++qtd->isoc_frame_index == urb->packet_count) {
-+ /*
-+ * urb->status is not used for isoc transfers.
-+ * The individual frame_desc statuses are used instead.
-+ */
-+ hcd->fops->complete(hcd, urb->priv, urb, 0);
-+ ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
-+ } else {
-+ ret_val = DWC_OTG_HC_XFER_COMPLETE;
-+ }
-+ return ret_val;
-+}
-+
-+/**
-+ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
-+ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
-+ * still linked to the QH, the QH is added to the end of the inactive
-+ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
-+ * schedule if no more QTDs are linked to the QH.
-+ */
-+static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
-+{
-+ int continue_split = 0;
-+ dwc_otg_qtd_t *qtd;
-+
-+ DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
-+
-+ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
-+
-+ if (qtd->complete_split) {
-+ continue_split = 1;
-+ } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
-+ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
-+ continue_split = 1;
-+ }
-+
-+ if (free_qtd) {
-+ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
-+ continue_split = 0;
-+ }
-+
-+ qh->channel = NULL;
-+ dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
-+}
-+
-+/**
-+ * Releases a host channel for use by other transfers. Attempts to select and
-+ * queue more transactions since at least one host channel is available.
-+ *
-+ * @param hcd The HCD state structure.
-+ * @param hc The host channel to release.
-+ * @param qtd The QTD associated with the host channel. This QTD may be freed
-+ * if the transfer is complete or an error has occurred.
-+ * @param halt_status Reason the channel is being released. This status
-+ * determines the actions taken by this function.
-+ */
-+static void release_channel(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ dwc_otg_transaction_type_e tr_type;
-+ int free_qtd;
-+ dwc_irqflags_t flags;
-+ dwc_spinlock_t *channel_lock = hcd->channel_lock;
-+#ifdef FIQ_DEBUG
-+ int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0;
-+#endif
-+ int hog_port = 0;
-+
-+ DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
-+ __func__, hc->hc_num, halt_status, hc->xfer_len);
-+
-+ if(fiq_split_enable && hc->do_split) {
-+ if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) {
-+ if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID ||
-+ hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) {
-+ hog_port = 1;
-+ }
-+ }
-+ }
-+
-+ switch (halt_status) {
-+ case DWC_OTG_HC_XFER_URB_COMPLETE:
-+ free_qtd = 1;
-+ break;
-+ case DWC_OTG_HC_XFER_AHB_ERR:
-+ case DWC_OTG_HC_XFER_STALL:
-+ case DWC_OTG_HC_XFER_BABBLE_ERR:
-+ free_qtd = 1;
-+ break;
-+ case DWC_OTG_HC_XFER_XACT_ERR:
-+ if (qtd->error_count >= 3) {
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " Complete URB with transaction error\n");
-+ free_qtd = 1;
-+ qtd->urb->status = -DWC_E_PROTOCOL;
-+ hcd->fops->complete(hcd, qtd->urb->priv,
-+ qtd->urb, -DWC_E_PROTOCOL);
-+ } else {
-+ free_qtd = 0;
-+ }
-+ break;
-+ case DWC_OTG_HC_XFER_URB_DEQUEUE:
-+ /*
-+ * The QTD has already been removed and the QH has been
-+ * deactivated. Don't want to do anything except release the
-+ * host channel and try to queue more transfers.
-+ */
-+ goto cleanup;
-+ case DWC_OTG_HC_XFER_NO_HALT_STATUS:
-+ free_qtd = 0;
-+ break;
-+ case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE:
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " Complete URB with I/O error\n");
-+ free_qtd = 1;
-+ qtd->urb->status = -DWC_E_IO;
-+ hcd->fops->complete(hcd, qtd->urb->priv,
-+ qtd->urb, -DWC_E_IO);
-+ break;
-+ default:
-+ free_qtd = 0;
-+ break;
-+ }
-+
-+ deactivate_qh(hcd, hc->qh, free_qtd);
-+
-+cleanup:
-+ /*
-+ * Release the host channel for use by other transfers. The cleanup
-+ * function clears the channel interrupt enables and conditions, so
-+ * there's no need to clear the Channel Halted interrupt separately.
-+ */
-+ dwc_otg_hc_cleanup(hcd->core_if, hc);
-+ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
-+
-+ if (!microframe_schedule) {
-+ switch (hc->ep_type) {
-+ case DWC_OTG_EP_TYPE_CONTROL:
-+ case DWC_OTG_EP_TYPE_BULK:
-+ hcd->non_periodic_channels--;
-+ break;
-+
-+ default:
-+ /*
-+ * Don't release reservations for periodic channels here.
-+ * That's done when a periodic transfer is descheduled (i.e.
-+ * when the QH is removed from the periodic schedule).
-+ */
-+ break;
-+ }
-+ } else {
-+
-+ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
-+ hcd->available_host_channels++;
-+ fiq_print(FIQDBG_PORTHUB, "AHC = %d ", hcd->available_host_channels);
-+ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+ }
-+
-+ if(fiq_split_enable && hc->do_split)
-+ {
-+ if(!(hcd->hub_port[hc->hub_addr] & (1 << hc->port_addr)))
-+ {
-+ fiq_print(FIQDBG_ERR, "PRTNOTAL");
-+ //BUG();
-+ }
-+ if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_INTR)) {
-+ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr);
-+#ifdef FIQ_DEBUG
-+ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1;
-+#endif
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp);
-+ }
-+ }
-+
-+ /* Try to queue more transfers now that there's a free channel. */
-+ tr_type = dwc_otg_hcd_select_transactions(hcd);
-+ if (tr_type != DWC_OTG_TRANSACTION_NONE) {
-+ dwc_otg_hcd_queue_transactions(hcd, tr_type);
-+ }
-+}
-+
-+/**
-+ * Halts a host channel. If the channel cannot be halted immediately because
-+ * the request queue is full, this function ensures that the FIFO empty
-+ * interrupt for the appropriate queue is enabled so that the halt request can
-+ * be queued when there is space in the request queue.
-+ *
-+ * This function may also be called in DMA mode. In that case, the channel is
-+ * simply released since the core always halts the channel automatically in
-+ * DMA mode.
-+ */
-+static void halt_channel(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
-+{
-+ if (hcd->core_if->dma_enable) {
-+ release_channel(hcd, hc, qtd, halt_status);
-+ return;
-+ }
-+
-+ /* Slave mode processing... */
-+ dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
-+
-+ if (hc->halt_on_queue) {
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+ dwc_otg_core_global_regs_t *global_regs;
-+ global_regs = hcd->core_if->core_global_regs;
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
-+ /*
-+ * Make sure the Non-periodic Tx FIFO empty interrupt
-+ * is enabled so that the non-periodic schedule will
-+ * be processed.
-+ */
-+ gintmsk.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
-+ } else {
-+ /*
-+ * Move the QH from the periodic queued schedule to
-+ * the periodic assigned schedule. This allows the
-+ * halt to be queued when the periodic schedule is
-+ * processed.
-+ */
-+ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
-+ &hc->qh->qh_list_entry);
-+
-+ /*
-+ * Make sure the Periodic Tx FIFO Empty interrupt is
-+ * enabled so that the periodic schedule will be
-+ * processed.
-+ */
-+ gintmsk.b.ptxfempty = 1;
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
-+ }
-+ }
-+}
-+
-+/**
-+ * Performs common cleanup for non-periodic transfers after a Transfer
-+ * Complete interrupt. This function should be called after any endpoint type
-+ * specific handling is finished to release the host channel.
-+ */
-+static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ hcint_data_t hcint;
-+
-+ qtd->error_count = 0;
-+
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ if (hcint.b.nyet) {
-+ /*
-+ * Got a NYET on the last transaction of the transfer. This
-+ * means that the endpoint should be in the PING state at the
-+ * beginning of the next transfer.
-+ */
-+ hc->qh->ping_state = 1;
-+ clear_hc_int(hc_regs, nyet);
-+ }
-+
-+ /*
-+ * Always halt and release the host channel to make it available for
-+ * more transfers. There may still be more phases for a control
-+ * transfer or more data packets for a bulk transfer at this point,
-+ * but the host channel is still halted. A channel will be reassigned
-+ * to the transfer when the non-periodic schedule is processed after
-+ * the channel is released. This allows transactions to be queued
-+ * properly via dwc_otg_hcd_queue_transactions, which also enables the
-+ * Tx FIFO Empty interrupt if necessary.
-+ */
-+ if (hc->ep_is_in) {
-+ /*
-+ * IN transfers in Slave mode require an explicit disable to
-+ * halt the channel. (In DMA mode, this call simply releases
-+ * the channel.)
-+ */
-+ halt_channel(hcd, hc, qtd, halt_status);
-+ } else {
-+ /*
-+ * The channel is automatically disabled by the core for OUT
-+ * transfers in Slave mode.
-+ */
-+ release_channel(hcd, hc, qtd, halt_status);
-+ }
-+}
-+
-+/**
-+ * Performs common cleanup for periodic transfers after a Transfer Complete
-+ * interrupt. This function should be called after any endpoint type specific
-+ * handling is finished to release the host channel.
-+ */
-+static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ hctsiz_data_t hctsiz;
-+ qtd->error_count = 0;
-+
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+ if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
-+ /* Core halts channel in these cases. */
-+ release_channel(hcd, hc, qtd, halt_status);
-+ } else {
-+ /* Flush any outstanding requests from the Tx queue. */
-+ halt_channel(hcd, hc, qtd, halt_status);
-+ }
-+}
-+
-+static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ uint32_t len;
-+ struct dwc_otg_hcd_iso_packet_desc *frame_desc;
-+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
-+
-+ len = get_actual_xfer_length(hc, hc_regs, qtd,
-+ DWC_OTG_HC_XFER_COMPLETE, NULL);
-+
-+ if (!len) {
-+ qtd->complete_split = 0;
-+ qtd->isoc_split_offset = 0;
-+ return 0;
-+ }
-+ frame_desc->actual_length += len;
-+
-+ if (hc->align_buff && len)
-+ dwc_memcpy(qtd->urb->buf + frame_desc->offset +
-+ qtd->isoc_split_offset, hc->qh->dw_align_buf, len);
-+ qtd->isoc_split_offset += len;
-+
-+ if (frame_desc->length == frame_desc->actual_length) {
-+ frame_desc->status = 0;
-+ qtd->isoc_frame_index++;
-+ qtd->complete_split = 0;
-+ qtd->isoc_split_offset = 0;
-+ }
-+
-+ if (qtd->isoc_frame_index == qtd->urb->packet_count) {
-+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
-+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
-+ } else {
-+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
-+ }
-+
-+ return 1; /* Indicates that channel released */
-+}
-+
-+/**
-+ * Handles a host channel Transfer Complete interrupt. This handler may be
-+ * called in either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ int urb_xfer_done;
-+ dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
-+ dwc_otg_hcd_urb_t *urb = qtd->urb;
-+ int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
-+
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "Transfer Complete--\n", hc->hc_num);
-+
-+ if (hcd->core_if->dma_desc_enable) {
-+ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
-+ if (pipe_type == UE_ISOCHRONOUS) {
-+ /* Do not disable the interrupt, just clear it */
-+ clear_hc_int(hc_regs, xfercomp);
-+ return 1;
-+ }
-+ goto handle_xfercomp_done;
-+ }
-+
-+ /*
-+ * Handle xfer complete on CSPLIT.
-+ */
-+
-+ if (hc->qh->do_split) {
-+ if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
-+ && hcd->core_if->dma_enable) {
-+ if (qtd->complete_split
-+ && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs,
-+ qtd))
-+ goto handle_xfercomp_done;
-+ } else {
-+ qtd->complete_split = 0;
-+ }
-+ }
-+
-+ /* Update the QTD and URB states. */
-+ switch (pipe_type) {
-+ case UE_CONTROL:
-+ switch (qtd->control_phase) {
-+ case DWC_OTG_CONTROL_SETUP:
-+ if (urb->length > 0) {
-+ qtd->control_phase = DWC_OTG_CONTROL_DATA;
-+ } else {
-+ qtd->control_phase = DWC_OTG_CONTROL_STATUS;
-+ }
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " Control setup transaction done\n");
-+ halt_status = DWC_OTG_HC_XFER_COMPLETE;
-+ break;
-+ case DWC_OTG_CONTROL_DATA:{
-+ urb_xfer_done =
-+ update_urb_state_xfer_comp(hc, hc_regs, urb,
-+ qtd);
-+ if (urb_xfer_done) {
-+ qtd->control_phase =
-+ DWC_OTG_CONTROL_STATUS;
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " Control data transfer done\n");
-+ } else {
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ }
-+ halt_status = DWC_OTG_HC_XFER_COMPLETE;
-+ break;
-+ }
-+ case DWC_OTG_CONTROL_STATUS:
-+ DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
-+ if (urb->status == -DWC_E_IN_PROGRESS) {
-+ urb->status = 0;
-+ }
-+ hcd->fops->complete(hcd, urb->priv, urb, urb->status);
-+ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
-+ break;
-+ }
-+
-+ complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
-+ break;
-+ case UE_BULK:
-+ DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
-+ urb_xfer_done =
-+ update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
-+ if (urb_xfer_done) {
-+ hcd->fops->complete(hcd, urb->priv, urb, urb->status);
-+ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
-+ } else {
-+ halt_status = DWC_OTG_HC_XFER_COMPLETE;
-+ }
-+
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
-+ break;
-+ case UE_INTERRUPT:
-+ DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
-+ urb_xfer_done =
-+ update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
-+
-+ /*
-+ * Interrupt URB is done on the first transfer complete
-+ * interrupt.
-+ */
-+ if (urb_xfer_done) {
-+ hcd->fops->complete(hcd, urb->priv, urb, urb->status);
-+ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
-+ } else {
-+ halt_status = DWC_OTG_HC_XFER_COMPLETE;
-+ }
-+
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
-+ break;
-+ case UE_ISOCHRONOUS:
-+ DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
-+ if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
-+ halt_status =
-+ update_isoc_urb_state(hcd, hc, hc_regs, qtd,
-+ DWC_OTG_HC_XFER_COMPLETE);
-+ }
-+ complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
-+ break;
-+ }
-+
-+handle_xfercomp_done:
-+ disable_hc_int(hc_regs, xfercompl);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel STALL interrupt. This handler may be called in
-+ * either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ dwc_otg_hcd_urb_t *urb = qtd->urb;
-+ int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
-+
-+ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
-+ "STALL Received--\n", hc->hc_num);
-+
-+ if (hcd->core_if->dma_desc_enable) {
-+ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
-+ goto handle_stall_done;
-+ }
-+
-+ if (pipe_type == UE_CONTROL) {
-+ hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
-+ }
-+
-+ if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
-+ hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
-+ /*
-+ * USB protocol requires resetting the data toggle for bulk
-+ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
-+ * setup command is issued to the endpoint. Anticipate the
-+ * CLEAR_FEATURE command since a STALL has occurred and reset
-+ * the data toggle now.
-+ */
-+ hc->qh->data_toggle = 0;
-+ }
-+
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
-+
-+handle_stall_done:
-+ disable_hc_int(hc_regs, stall);
-+
-+ return 1;
-+}
-+
-+/*
-+ * Updates the state of the URB when a transfer has been stopped due to an
-+ * abnormal condition before the transfer completes. Modifies the
-+ * actual_length field of the URB to reflect the number of bytes that have
-+ * actually been transferred via the host channel.
-+ */
-+static void update_urb_state_xfer_intr(dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_hcd_urb_t * urb,
-+ dwc_otg_qtd_t * qtd,
-+ dwc_otg_halt_status_e halt_status)
-+{
-+ uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
-+ halt_status, NULL);
-+ /* non DWORD-aligned buffer case handling. */
-+ if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
-+ dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
-+ bytes_transferred);
-+ }
-+
-+ urb->actual_length += bytes_transferred;
-+
-+#ifdef DEBUG
-+ {
-+ hctsiz_data_t hctsiz;
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
-+ __func__, (hc->ep_is_in ? "IN" : "OUT"),
-+ hc->hc_num);
-+ DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n",
-+ hc->start_pkt_count);
-+ DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
-+ DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet);
-+ DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n",
-+ bytes_transferred);
-+ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n",
-+ urb->actual_length);
-+ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
-+ urb->length);
-+ }
-+#endif
-+}
-+
-+/**
-+ * Handles a host channel NAK interrupt. This handler may be called in either
-+ * DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "NAK Received--\n", hc->hc_num);
-+
-+ /*
-+ * When we get bulk NAKs then remember this so we holdoff on this qh until
-+ * the beginning of the next frame
-+ */
-+ switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-+ case UE_BULK:
-+ case UE_CONTROL:
-+ if (nak_holdoff_enable)
-+ hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd);
-+ }
-+
-+ /*
-+ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
-+ * interrupt. Re-start the SSPLIT transfer.
-+ */
-+ if (hc->do_split) {
-+ if (hc->complete_split) {
-+ qtd->error_count = 0;
-+ }
-+ qtd->complete_split = 0;
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
-+ goto handle_nak_done;
-+ }
-+
-+ switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-+ case UE_CONTROL:
-+ case UE_BULK:
-+ if (hcd->core_if->dma_enable && hc->ep_is_in) {
-+ /*
-+ * NAK interrupts are enabled on bulk/control IN
-+ * transfers in DMA mode for the sole purpose of
-+ * resetting the error count after a transaction error
-+ * occurs. The core will continue transferring data.
-+ * Disable other interrupts unmasked for the same
-+ * reason.
-+ */
-+ disable_hc_int(hc_regs, datatglerr);
-+ disable_hc_int(hc_regs, ack);
-+ qtd->error_count = 0;
-+ goto handle_nak_done;
-+ }
-+
-+ /*
-+ * NAK interrupts normally occur during OUT transfers in DMA
-+ * or Slave mode. For IN transfers, more requests will be
-+ * queued as request queue space is available.
-+ */
-+ qtd->error_count = 0;
-+
-+ if (!hc->qh->ping_state) {
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd,
-+ DWC_OTG_HC_XFER_NAK);
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+
-+ if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
-+ hc->qh->ping_state = 1;
-+ }
-+
-+ /*
-+ * Halt the channel so the transfer can be re-started from
-+ * the appropriate point or the PING protocol will
-+ * start/continue.
-+ */
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
-+ break;
-+ case UE_INTERRUPT:
-+ qtd->error_count = 0;
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
-+ break;
-+ case UE_ISOCHRONOUS:
-+ /* Should never get called for isochronous transfers. */
-+ DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
-+ break;
-+ }
-+
-+handle_nak_done:
-+ disable_hc_int(hc_regs, nak);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel ACK interrupt. This interrupt is enabled when
-+ * performing the PING protocol in Slave mode, when errors occur during
-+ * either Slave mode or DMA mode, and during Start Split transactions.
-+ */
-+static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "ACK Received--\n", hc->hc_num);
-+
-+ if (hc->do_split) {
-+ /*
-+ * Handle ACK on SSPLIT.
-+ * ACK should not occur in CSPLIT.
-+ */
-+ if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
-+ qtd->ssplit_out_xfer_count = hc->xfer_len;
-+ }
-+ if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
-+ /* Don't need complete for isochronous out transfers. */
-+ qtd->complete_split = 1;
-+ }
-+
-+ /* ISOC OUT */
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
-+ switch (hc->xact_pos) {
-+ case DWC_HCSPLIT_XACTPOS_ALL:
-+ break;
-+ case DWC_HCSPLIT_XACTPOS_END:
-+ qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
-+ qtd->isoc_split_offset = 0;
-+ break;
-+ case DWC_HCSPLIT_XACTPOS_BEGIN:
-+ case DWC_HCSPLIT_XACTPOS_MID:
-+ /*
-+ * For BEGIN or MID, calculate the length for
-+ * the next microframe to determine the correct
-+ * SSPLIT token, either MID or END.
-+ */
-+ {
-+ struct dwc_otg_hcd_iso_packet_desc
-+ *frame_desc;
-+
-+ frame_desc =
-+ &qtd->urb->
-+ iso_descs[qtd->isoc_frame_index];
-+ qtd->isoc_split_offset += 188;
-+
-+ if ((frame_desc->length -
-+ qtd->isoc_split_offset) <= 188) {
-+ qtd->isoc_split_pos =
-+ DWC_HCSPLIT_XACTPOS_END;
-+ } else {
-+ qtd->isoc_split_pos =
-+ DWC_HCSPLIT_XACTPOS_MID;
-+ }
-+
-+ }
-+ break;
-+ }
-+ } else {
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
-+ }
-+ } else {
-+ /*
-+ * An unmasked ACK on a non-split DMA transaction is
-+ * for the sole purpose of resetting error counts. Disable other
-+ * interrupts unmasked for the same reason.
-+ */
-+ if(hcd->core_if->dma_enable) {
-+ disable_hc_int(hc_regs, datatglerr);
-+ disable_hc_int(hc_regs, nak);
-+ }
-+ qtd->error_count = 0;
-+
-+ if (hc->qh->ping_state) {
-+ hc->qh->ping_state = 0;
-+ /*
-+ * Halt the channel so the transfer can be re-started
-+ * from the appropriate point. This only happens in
-+ * Slave mode. In DMA mode, the ping_state is cleared
-+ * when the transfer is started because the core
-+ * automatically executes the PING, then the transfer.
-+ */
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
-+ }
-+ }
-+
-+ /*
-+ * If the ACK occurred when _not_ in the PING state, let the channel
-+ * continue transferring data after clearing the error count.
-+ */
-+
-+ disable_hc_int(hc_regs, ack);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel NYET interrupt. This interrupt should only occur on
-+ * Bulk and Control OUT endpoints and for complete split transactions. If a
-+ * NYET occurs at the same time as a Transfer Complete interrupt, it is
-+ * handled in the xfercomp interrupt handler, not here. This handler may be
-+ * called in either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "NYET Received--\n", hc->hc_num);
-+
-+ /*
-+ * NYET on CSPLIT
-+ * re-do the CSPLIT immediately on non-periodic
-+ */
-+ if (hc->do_split && hc->complete_split) {
-+ if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
-+ && hcd->core_if->dma_enable) {
-+ qtd->complete_split = 0;
-+ qtd->isoc_split_offset = 0;
-+ if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
-+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
-+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
-+ }
-+ else
-+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
-+ goto handle_nyet_done;
-+ }
-+
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ int frnum = dwc_otg_hcd_get_frame_number(hcd);
-+
-+ // With the FIQ running we only ever see the failed NYET
-+ if (dwc_full_frame_num(frnum) !=
-+ dwc_full_frame_num(hc->qh->sched_frame) ||
-+ fiq_split_enable) {
-+ /*
-+ * No longer in the same full speed frame.
-+ * Treat this as a transaction error.
-+ */
-+#if 0
-+ /** @todo Fix system performance so this can
-+ * be treated as an error. Right now complete
-+ * splits cannot be scheduled precisely enough
-+ * due to other system activity, so this error
-+ * occurs regularly in Slave mode.
-+ */
-+ qtd->error_count++;
-+#endif
-+ qtd->complete_split = 0;
-+ halt_channel(hcd, hc, qtd,
-+ DWC_OTG_HC_XFER_XACT_ERR);
-+ /** @todo add support for isoc release */
-+ goto handle_nyet_done;
-+ }
-+ }
-+
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
-+ goto handle_nyet_done;
-+ }
-+
-+ hc->qh->ping_state = 1;
-+ qtd->error_count = 0;
-+
-+ update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
-+ DWC_OTG_HC_XFER_NYET);
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+
-+ /*
-+ * Halt the channel and re-start the transfer so the PING
-+ * protocol will start.
-+ */
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
-+
-+handle_nyet_done:
-+ disable_hc_int(hc_regs, nyet);
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel babble interrupt. This handler may be called in
-+ * either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "Babble Error--\n", hc->hc_num);
-+
-+ if (hcd->core_if->dma_desc_enable) {
-+ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
-+ DWC_OTG_HC_XFER_BABBLE_ERR);
-+ goto handle_babble_done;
-+ }
-+
-+ if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
-+ hcd->fops->complete(hcd, qtd->urb->priv,
-+ qtd->urb, -DWC_E_OVERFLOW);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
-+ } else {
-+ dwc_otg_halt_status_e halt_status;
-+ halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
-+ DWC_OTG_HC_XFER_BABBLE_ERR);
-+ halt_channel(hcd, hc, qtd, halt_status);
-+ }
-+
-+handle_babble_done:
-+ disable_hc_int(hc_regs, bblerr);
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel AHB error interrupt. This handler is only called in
-+ * DMA mode.
-+ */
-+static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ hcchar_data_t hcchar;
-+ hcsplt_data_t hcsplt;
-+ hctsiz_data_t hctsiz;
-+ uint32_t hcdma;
-+ char *pipetype, *speed;
-+
-+ dwc_otg_hcd_urb_t *urb = qtd->urb;
-+
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "AHB Error--\n", hc->hc_num);
-+
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+ hcdma = DWC_READ_REG32(&hc_regs->hcdma);
-+
-+ DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
-+ DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
-+ DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
-+ DWC_ERROR(" Device address: %d\n",
-+ dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
-+ DWC_ERROR(" Endpoint: %d, %s\n",
-+ dwc_otg_hcd_get_ep_num(&urb->pipe_info),
-+ (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
-+
-+ switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
-+ case UE_CONTROL:
-+ pipetype = "CONTROL";
-+ break;
-+ case UE_BULK:
-+ pipetype = "BULK";
-+ break;
-+ case UE_INTERRUPT:
-+ pipetype = "INTERRUPT";
-+ break;
-+ case UE_ISOCHRONOUS:
-+ pipetype = "ISOCHRONOUS";
-+ break;
-+ default:
-+ pipetype = "UNKNOWN";
-+ break;
-+ }
-+
-+ DWC_ERROR(" Endpoint type: %s\n", pipetype);
-+
-+ switch (hc->speed) {
-+ case DWC_OTG_EP_SPEED_HIGH:
-+ speed = "HIGH";
-+ break;
-+ case DWC_OTG_EP_SPEED_FULL:
-+ speed = "FULL";
-+ break;
-+ case DWC_OTG_EP_SPEED_LOW:
-+ speed = "LOW";
-+ break;
-+ default:
-+ speed = "UNKNOWN";
-+ break;
-+ };
-+
-+ DWC_ERROR(" Speed: %s\n", speed);
-+
-+ DWC_ERROR(" Max packet size: %d\n",
-+ dwc_otg_hcd_get_mps(&urb->pipe_info));
-+ DWC_ERROR(" Data buffer length: %d\n", urb->length);
-+ DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
-+ urb->buf, (void *)urb->dma);
-+ DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
-+ urb->setup_packet, (void *)urb->setup_dma);
-+ DWC_ERROR(" Interval: %d\n", urb->interval);
-+
-+ /* Core haltes the channel for Descriptor DMA mode */
-+ if (hcd->core_if->dma_desc_enable) {
-+ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
-+ DWC_OTG_HC_XFER_AHB_ERR);
-+ goto handle_ahberr_done;
-+ }
-+
-+ hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
-+
-+ /*
-+ * Force a channel halt. Don't call halt_channel because that won't
-+ * write to the HCCHARn register in DMA mode to force the halt.
-+ */
-+ dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
-+handle_ahberr_done:
-+ disable_hc_int(hc_regs, ahberr);
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel transaction error interrupt. This handler may be
-+ * called in either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "Transaction Error--\n", hc->hc_num);
-+
-+ if (hcd->core_if->dma_desc_enable) {
-+ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
-+ DWC_OTG_HC_XFER_XACT_ERR);
-+ goto handle_xacterr_done;
-+ }
-+
-+ switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-+ case UE_CONTROL:
-+ case UE_BULK:
-+ qtd->error_count++;
-+ if (!hc->qh->ping_state) {
-+
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd,
-+ DWC_OTG_HC_XFER_XACT_ERR);
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
-+ hc->qh->ping_state = 1;
-+ }
-+ }
-+
-+ /*
-+ * Halt the channel so the transfer can be re-started from
-+ * the appropriate point or the PING protocol will start.
-+ */
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ break;
-+ case UE_INTERRUPT:
-+ qtd->error_count++;
-+ if (hc->do_split && hc->complete_split) {
-+ qtd->complete_split = 0;
-+ }
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ break;
-+ case UE_ISOCHRONOUS:
-+ {
-+ dwc_otg_halt_status_e halt_status;
-+ halt_status =
-+ update_isoc_urb_state(hcd, hc, hc_regs, qtd,
-+ DWC_OTG_HC_XFER_XACT_ERR);
-+
-+ halt_channel(hcd, hc, qtd, halt_status);
-+ }
-+ break;
-+ }
-+handle_xacterr_done:
-+ disable_hc_int(hc_regs, xacterr);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel frame overrun interrupt. This handler may be called
-+ * in either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "Frame Overrun--\n", hc->hc_num);
-+
-+ switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-+ case UE_CONTROL:
-+ case UE_BULK:
-+ break;
-+ case UE_INTERRUPT:
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
-+ break;
-+ case UE_ISOCHRONOUS:
-+ {
-+ dwc_otg_halt_status_e halt_status;
-+ halt_status =
-+ update_isoc_urb_state(hcd, hc, hc_regs, qtd,
-+ DWC_OTG_HC_XFER_FRAME_OVERRUN);
-+
-+ halt_channel(hcd, hc, qtd, halt_status);
-+ }
-+ break;
-+ }
-+
-+ disable_hc_int(hc_regs, frmovrun);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handles a host channel data toggle error interrupt. This handler may be
-+ * called in either DMA mode or Slave mode.
-+ */
-+static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "Data Toggle Error on %s transfer--\n",
-+ hc->hc_num, (hc->ep_is_in ? "IN" : "OUT"));
-+
-+ /* Data toggles on split transactions cause the hc to halt.
-+ * restart transfer */
-+ if(hc->qh->do_split)
-+ {
-+ qtd->error_count++;
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ } else if (hc->ep_is_in) {
-+ /* An unmasked data toggle error on a non-split DMA transaction is
-+ * for the sole purpose of resetting error counts. Disable other
-+ * interrupts unmasked for the same reason.
-+ */
-+ if(hcd->core_if->dma_enable) {
-+ disable_hc_int(hc_regs, ack);
-+ disable_hc_int(hc_regs, nak);
-+ }
-+ qtd->error_count = 0;
-+ }
-+
-+ disable_hc_int(hc_regs, datatglerr);
-+
-+ return 1;
-+}
-+
-+#ifdef DEBUG
-+/**
-+ * This function is for debug only. It checks that a valid halt status is set
-+ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
-+ * taken and a warning is issued.
-+ * @return 1 if halt status is ok, 0 otherwise.
-+ */
-+static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd)
-+{
-+ hcchar_data_t hcchar;
-+ hctsiz_data_t hctsiz;
-+ hcint_data_t hcint;
-+ hcintmsk_data_t hcintmsk;
-+ hcsplt_data_t hcsplt;
-+
-+ if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
-+ /*
-+ * This code is here only as a check. This condition should
-+ * never happen. Ignore the halt if it does occur.
-+ */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
-+ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
-+ DWC_WARN
-+ ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
-+ "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
-+ "hcint 0x%08x, hcintmsk 0x%08x, "
-+ "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
-+ hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
-+ hcintmsk.d32, hcsplt.d32, qtd->complete_split);
-+
-+ DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
-+ __func__, hc->hc_num);
-+ DWC_WARN("\n");
-+ clear_hc_int(hc_regs, chhltd);
-+ return 0;
-+ }
-+
-+ /*
-+ * This code is here only as a check. hcchar.chdis should
-+ * never be set when the halt interrupt occurs. Halt the
-+ * channel again if it does occur.
-+ */
-+ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
-+ if (hcchar.b.chdis) {
-+ DWC_WARN("%s: hcchar.chdis set unexpectedly, "
-+ "hcchar 0x%08x, trying to halt again\n",
-+ __func__, hcchar.d32);
-+ clear_hc_int(hc_regs, chhltd);
-+ hc->halt_pending = 0;
-+ halt_channel(hcd, hc, qtd, hc->halt_status);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+#endif
-+
-+/**
-+ * Handles a host Channel Halted interrupt in DMA mode. This handler
-+ * determines the reason the channel halted and proceeds accordingly.
-+ */
-+static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd,
-+ hcint_data_t hcint,
-+ hcintmsk_data_t hcintmsk)
-+{
-+ int out_nak_enh = 0;
-+
-+ /* For core with OUT NAK enhancement, the flow for high-
-+ * speed CONTROL/BULK OUT is handled a little differently.
-+ */
-+ if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
-+ if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
-+ (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
-+ out_nak_enh = 1;
-+ }
-+ }
-+
-+ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
-+ (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR
-+ && !hcd->core_if->dma_desc_enable)) {
-+ /*
-+ * Just release the channel. A dequeue can happen on a
-+ * transfer timeout. In the case of an AHB Error, the channel
-+ * was forced to halt because there's no way to gracefully
-+ * recover.
-+ */
-+ if (hcd->core_if->dma_desc_enable)
-+ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs,
-+ hc->halt_status);
-+ else
-+ release_channel(hcd, hc, qtd, hc->halt_status);
-+ return;
-+ }
-+
-+ /* Read the HCINTn register to determine the cause for the halt. */
-+ if(!fiq_split_enable)
-+ {
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
-+ }
-+
-+ if (hcint.b.xfercomp) {
-+ /** @todo This is here because of a possible hardware bug. Spec
-+ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
-+ * interrupt w/ACK bit set should occur, but I only see the
-+ * XFERCOMP bit, even with it masked out. This is a workaround
-+ * for that behavior. Should fix this when hardware is fixed.
-+ */
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
-+ handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
-+ }
-+ handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.stall) {
-+ handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
-+ if (out_nak_enh) {
-+ if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
-+ DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n");
-+ qtd->error_count = 0;
-+ } else {
-+ DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n");
-+ }
-+ }
-+
-+ /*
-+ * Must handle xacterr before nak or ack. Could get a xacterr
-+ * at the same time as either of these on a BULK/CONTROL OUT
-+ * that started with a PING. The xacterr takes precedence.
-+ */
-+ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
-+ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {
-+ handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.bblerr) {
-+ handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.frmovrun) {
-+ handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.datatglerr) {
-+ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd);
-+ } else if (!out_nak_enh) {
-+ if (hcint.b.nyet) {
-+ /*
-+ * Must handle nyet before nak or ack. Could get a nyet at the
-+ * same time as either of those on a BULK/CONTROL OUT that
-+ * started with a PING. The nyet takes precedence.
-+ */
-+ handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.nak && !hcintmsk.b.nak) {
-+ /*
-+ * If nak is not masked, it's because a non-split IN transfer
-+ * is in an error state. In that case, the nak is handled by
-+ * the nak interrupt handler, not here. Handle nak here for
-+ * BULK/CONTROL OUT transfers, which halt on a NAK to allow
-+ * rewinding the buffer pointer.
-+ */
-+ handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.ack && !hcintmsk.b.ack) {
-+ /*
-+ * If ack is not masked, it's because a non-split IN transfer
-+ * is in an error state. In that case, the ack is handled by
-+ * the ack interrupt handler, not here. Handle ack here for
-+ * split transfers. Start splits halt on ACK.
-+ */
-+ handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
-+ } else {
-+ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
-+ /*
-+ * A periodic transfer halted with no other channel
-+ * interrupts set. Assume it was halted by the core
-+ * because it could not be completed in its scheduled
-+ * (micro)frame.
-+ */
-+#ifdef DEBUG
-+ DWC_PRINTF
-+ ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
-+ __func__, hc->hc_num);
-+#endif
-+ halt_channel(hcd, hc, qtd,
-+ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
-+ } else {
-+ DWC_ERROR
-+ ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
-+ "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
-+ __func__, hc->hc_num, hcint.d32,
-+ DWC_READ_REG32(&hcd->
-+ core_if->core_global_regs->
-+ gintsts));
-+ /* Failthrough: use 3-strikes rule */
-+ qtd->error_count++;
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ }
-+
-+ }
-+ } else {
-+ DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
-+ hcint.d32);
-+ /* Failthrough: use 3-strikes rule */
-+ qtd->error_count++;
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ }
-+}
-+
-+/**
-+ * Handles a host channel Channel Halted interrupt.
-+ *
-+ * In slave mode, this handler is called only when the driver specifically
-+ * requests a halt. This occurs during handling other host channel interrupts
-+ * (e.g. nak, xacterr, stall, nyet, etc.).
-+ *
-+ * In DMA mode, this is the interrupt that occurs when the core has finished
-+ * processing a transfer on a channel. Other host channel interrupts (except
-+ * ahberr) are disabled in DMA mode.
-+ */
-+static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
-+ dwc_hc_t * hc,
-+ dwc_otg_hc_regs_t * hc_regs,
-+ dwc_otg_qtd_t * qtd,
-+ hcint_data_t hcint,
-+ hcintmsk_data_t hcintmsk)
-+{
-+ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-+ "Channel Halted--\n", hc->hc_num);
-+
-+ if (hcd->core_if->dma_enable) {
-+ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk);
-+ } else {
-+#ifdef DEBUG
-+ if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
-+ return 1;
-+ }
-+#endif
-+ release_channel(hcd, hc, qtd, hc->halt_status);
-+ }
-+
-+ return 1;
-+}
-+
-+/** Handles interrupt for a specific Host Channel */
-+int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
-+{
-+ int retval = 0;
-+ hcint_data_t hcint, hcint_orig;
-+ hcintmsk_data_t hcintmsk;
-+ dwc_hc_t *hc;
-+ dwc_otg_hc_regs_t *hc_regs;
-+ dwc_otg_qtd_t *qtd;
-+
-+ DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
-+
-+ hc = dwc_otg_hcd->hc_ptr_array[num];
-+ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
-+ if(hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
-+ /* We are responding to a channel disable. Driver
-+ * state is cleared - our qtd has gone away.
-+ */
-+ release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status);
-+ return 1;
-+ }
-+ qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
-+
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ hcint_orig = hcint;
-+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
-+ DWC_DEBUGPL(DBG_HCDV,
-+ " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
-+ hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
-+ hcint.d32 = hcint.d32 & hcintmsk.d32;
-+
-+ if(fiq_split_enable)
-+ {
-+ // replace with the saved interrupts from the fiq handler
-+ local_fiq_disable();
-+ hcint_orig.d32 = hcint_saved[num].d32;
-+ hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32;
-+ hcint_saved[num].d32 = 0;
-+ local_fiq_enable();
-+ }
-+
-+ if (!dwc_otg_hcd->core_if->dma_enable) {
-+ if (hcint.b.chhltd && hcint.d32 != 0x2) {
-+ hcint.b.chhltd = 0;
-+ }
-+ }
-+
-+ if (hcint.b.xfercomp) {
-+ retval |=
-+ handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ /*
-+ * If NYET occurred at same time as Xfer Complete, the NYET is
-+ * handled by the Xfer Complete interrupt handler. Don't want
-+ * to call the NYET interrupt handler in this case.
-+ */
-+ hcint.b.nyet = 0;
-+ }
-+ if (hcint.b.chhltd) {
-+ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]);
-+ }
-+ if (hcint.b.ahberr) {
-+ retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.stall) {
-+ retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.nak) {
-+ retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.ack) {
-+ if(!hcint.b.chhltd)
-+ retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.nyet) {
-+ retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.xacterr) {
-+ retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.bblerr) {
-+ retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.frmovrun) {
-+ retval |=
-+ handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+ if (hcint.b.datatglerr) {
-+ retval |=
-+ handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ }
-+
-+ return retval;
-+}
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,972 @@
-+
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
-+ * $Revision: #20 $
-+ * $Date: 2011/10/26 $
-+ * $Change: 1872981 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the implementation of the HCD. In Linux, the HCD
-+ * implements the hc_driver API.
-+ */
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/errno.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/string.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/version.h>
-+#include <asm/io.h>
-+#include <asm/fiq.h>
-+#include <linux/usb.h>
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
-+#include <../drivers/usb/core/hcd.h>
-+#else
-+#include <linux/usb/hcd.h>
-+#endif
-+
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
-+#define USB_URB_EP_LINKING 1
-+#else
-+#define USB_URB_EP_LINKING 0
-+#endif
-+
-+#include "dwc_otg_hcd_if.h"
-+#include "dwc_otg_dbg.h"
-+#include "dwc_otg_driver.h"
-+#include "dwc_otg_hcd.h"
-+#include "dwc_otg_mphi_fix.h"
-+
-+/**
-+ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
-+ * qualified with its direction (possible 32 endpoints per device).
-+ */
-+#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
-+ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
-+
-+static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
-+
-+extern bool fiq_fix_enable;
-+
-+/** @name Linux HC Driver API Functions */
-+/** @{ */
-+/* manage i/o requests, device state */
-+static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ struct usb_host_endpoint *ep,
-+#endif
-+ struct urb *urb, gfp_t mem_flags);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
-+#endif
-+#else /* kernels at or post 2.6.30 */
-+static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
-+ struct urb *urb, int status);
-+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
-+
-+static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
-+static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
-+#endif
-+static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
-+extern int hcd_start(struct usb_hcd *hcd);
-+extern void hcd_stop(struct usb_hcd *hcd);
-+static int get_frame_number(struct usb_hcd *hcd);
-+extern int hub_status_data(struct usb_hcd *hcd, char *buf);
-+extern int hub_control(struct usb_hcd *hcd,
-+ u16 typeReq,
-+ u16 wValue, u16 wIndex, char *buf, u16 wLength);
-+
-+struct wrapper_priv_data {
-+ dwc_otg_hcd_t *dwc_otg_hcd;
-+};
-+
-+/** @} */
-+
-+static struct hc_driver dwc_otg_hc_driver = {
-+
-+ .description = dwc_otg_hcd_name,
-+ .product_desc = "DWC OTG Controller",
-+ .hcd_priv_size = sizeof(struct wrapper_priv_data),
-+
-+ .irq = dwc_otg_hcd_irq,
-+
-+ .flags = HCD_MEMORY | HCD_USB2,
-+
-+ //.reset =
-+ .start = hcd_start,
-+ //.suspend =
-+ //.resume =
-+ .stop = hcd_stop,
-+
-+ .urb_enqueue = dwc_otg_urb_enqueue,
-+ .urb_dequeue = dwc_otg_urb_dequeue,
-+ .endpoint_disable = endpoint_disable,
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
-+ .endpoint_reset = endpoint_reset,
-+#endif
-+ .get_frame_number = get_frame_number,
-+
-+ .hub_status_data = hub_status_data,
-+ .hub_control = hub_control,
-+ //.bus_suspend =
-+ //.bus_resume =
-+};
-+
-+/** Gets the dwc_otg_hcd from a struct usb_hcd */
-+static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
-+{
-+ struct wrapper_priv_data *p;
-+ p = (struct wrapper_priv_data *)(hcd->hcd_priv);
-+ return p->dwc_otg_hcd;
-+}
-+
-+/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
-+static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
-+{
-+ return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
-+}
-+
-+/** Gets the usb_host_endpoint associated with an URB. */
-+inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
-+{
-+ struct usb_device *dev = urb->dev;
-+ int ep_num = usb_pipeendpoint(urb->pipe);
-+
-+ if (usb_pipein(urb->pipe))
-+ return dev->ep_in[ep_num];
-+ else
-+ return dev->ep_out[ep_num];
-+}
-+
-+static int _disconnect(dwc_otg_hcd_t * hcd)
-+{
-+ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
-+
-+ usb_hcd->self.is_b_host = 0;
-+ return 0;
-+}
-+
-+static int _start(dwc_otg_hcd_t * hcd)
-+{
-+ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
-+
-+ usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
-+ hcd_start(usb_hcd);
-+
-+ return 0;
-+}
-+
-+static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
-+ uint32_t * port_addr)
-+{
-+ struct urb *urb = (struct urb *)urb_handle;
-+ struct usb_bus *bus;
-+#if 1 //GRAYG - temporary
-+ if (NULL == urb_handle)
-+ DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
-+ if (NULL == urb->dev)
-+ DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
-+ if (NULL == port_addr)
-+ DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
-+#endif
-+ if (urb->dev->tt) {
-+ if (NULL == urb->dev->tt->hub) {
-+ DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
-+ __func__); //GRAYG
-+ //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
-+ *hub_addr = 0; //GRAYG
-+ // we probably shouldn't have a transaction translator if
-+ // there's no associated hub?
-+ } else {
-+ bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
-+ if (urb->dev->tt->hub == bus->root_hub)
-+ *hub_addr = 0;
-+ else
-+ *hub_addr = urb->dev->tt->hub->devnum;
-+ }
-+ *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1;
-+ } else {
-+ *hub_addr = 0;
-+ *port_addr = urb->dev->ttport;
-+ }
-+ return 0;
-+}
-+
-+static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
-+{
-+ struct urb *urb = (struct urb *)urb_handle;
-+ return urb->dev->speed;
-+}
-+
-+static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
-+{
-+ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
-+ return usb_hcd->self.b_hnp_enable;
-+}
-+
-+static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
-+ struct urb *urb)
-+{
-+ hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
-+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-+ hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
-+ } else {
-+ hcd_to_bus(hcd)->bandwidth_int_reqs++;
-+ }
-+}
-+
-+static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
-+ struct urb *urb)
-+{
-+ hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
-+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-+ hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
-+ } else {
-+ hcd_to_bus(hcd)->bandwidth_int_reqs--;
-+ }
-+}
-+
-+/**
-+ * Sets the final status of an URB and returns it to the device driver. Any
-+ * required cleanup of the URB is performed. The HCD lock should be held on
-+ * entry.
-+ */
-+static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
-+ dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
-+{
-+ struct urb *urb = (struct urb *)urb_handle;
-+ urb_tq_entry_t *new_entry;
-+ int rc = 0;
-+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
-+ DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
-+ __func__, urb, usb_pipedevice(urb->pipe),
-+ usb_pipeendpoint(urb->pipe),
-+ usb_pipein(urb->pipe) ? "IN" : "OUT", status);
-+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-+ int i;
-+ for (i = 0; i < urb->number_of_packets; i++) {
-+ DWC_PRINTF(" ISO Desc %d status: %d\n",
-+ i, urb->iso_frame_desc[i].status);
-+ }
-+ }
-+ }
-+ new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t));
-+ urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
-+ /* Convert status value. */
-+ switch (status) {
-+ case -DWC_E_PROTOCOL:
-+ status = -EPROTO;
-+ break;
-+ case -DWC_E_IN_PROGRESS:
-+ status = -EINPROGRESS;
-+ break;
-+ case -DWC_E_PIPE:
-+ status = -EPIPE;
-+ break;
-+ case -DWC_E_IO:
-+ status = -EIO;
-+ break;
-+ case -DWC_E_TIMEOUT:
-+ status = -ETIMEDOUT;
-+ break;
-+ case -DWC_E_OVERFLOW:
-+ status = -EOVERFLOW;
-+ break;
-+ case -DWC_E_SHUTDOWN:
-+ status = -ESHUTDOWN;
-+ break;
-+ default:
-+ if (status) {
-+ DWC_PRINTF("Uknown urb status %d\n", status);
-+
-+ }
-+ }
-+
-+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-+ int i;
-+
-+ urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
-+ for (i = 0; i < urb->number_of_packets; ++i) {
-+ urb->iso_frame_desc[i].actual_length =
-+ dwc_otg_hcd_urb_get_iso_desc_actual_length
-+ (dwc_otg_urb, i);
-+ urb->iso_frame_desc[i].status =
-+ dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
-+ }
-+ }
-+
-+ urb->status = status;
-+ urb->hcpriv = NULL;
-+ if (!status) {
-+ if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-+ (urb->actual_length < urb->transfer_buffer_length)) {
-+ urb->status = -EREMOTEIO;
-+ }
-+ }
-+
-+ if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
-+ (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
-+ struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
-+ if (ep) {
-+ free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
-+ dwc_otg_hcd_get_ep_bandwidth(hcd,
-+ ep->hcpriv),
-+ urb);
-+ }
-+ }
-+
-+ DWC_FREE(dwc_otg_urb);
-+ if (!new_entry) {
-+ DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n");
-+ urb->status = -EPROTO;
-+ /* don't schedule the tasklet -
-+ * directly return the packet here with error. */
-+#if USB_URB_EP_LINKING
-+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
-+#endif
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
-+#else
-+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
-+#endif
-+ } else {
-+ new_entry->urb = urb;
-+#if USB_URB_EP_LINKING
-+ rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
-+ if(0 == rc) {
-+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
-+ }
-+#endif
-+ if(0 == rc) {
-+ DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
-+ urb_tq_entries);
-+ DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static struct dwc_otg_hcd_function_ops hcd_fops = {
-+ .start = _start,
-+ .disconnect = _disconnect,
-+ .hub_info = _hub_info,
-+ .speed = _speed,
-+ .complete = _complete,
-+ .get_b_hnp_enable = _get_b_hnp_enable,
-+};
-+
-+static struct fiq_handler fh = {
-+ .name = "usb_fiq",
-+};
-+struct fiq_stack_s {
-+ int magic1;
-+ uint8_t stack[2048];
-+ int magic2;
-+} fiq_stack;
-+
-+extern mphi_regs_t c_mphi_regs;
-+/**
-+ * Initializes the HCD. This function allocates memory for and initializes the
-+ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
-+ * USB bus with the core and calls the hc_driver->start() function. It returns
-+ * a negative error on failure.
-+ */
-+int hcd_init(dwc_bus_dev_t *_dev)
-+{
-+ struct usb_hcd *hcd = NULL;
-+ dwc_otg_hcd_t *dwc_otg_hcd = NULL;
-+ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
-+ int retval = 0;
-+ u64 dmamask;
-+ struct pt_regs regs;
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
-+
-+ /* Set device flags indicating whether the HCD supports DMA. */
-+ if (dwc_otg_is_dma_enable(otg_dev->core_if))
-+ dmamask = DMA_BIT_MASK(32);
-+ else
-+ dmamask = 0;
-+
-+#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
-+ dma_set_mask(&_dev->dev, dmamask);
-+ dma_set_coherent_mask(&_dev->dev, dmamask);
-+#elif defined(PCI_INTERFACE)
-+ pci_set_dma_mask(_dev, dmamask);
-+ pci_set_consistent_dma_mask(_dev, dmamask);
-+#endif
-+
-+ if (fiq_fix_enable)
-+ {
-+ // Set up fiq
-+ claim_fiq(&fh);
-+ set_fiq_handler(__FIQ_Branch, 4);
-+ memset(&regs,0,sizeof(regs));
-+ regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq;
-+ regs.ARM_r9 = (long)0;
-+ regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4;
-+ set_fiq_regs(&regs);
-+ fiq_stack.magic1 = 0xdeadbeef;
-+ fiq_stack.magic2 = 0xaa995566;
-+ }
-+
-+ /*
-+ * Allocate memory for the base HCD plus the DWC OTG HCD.
-+ * Initialize the base HCD.
-+ */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-+ hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
-+#else
-+ hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
-+ hcd->has_tt = 1;
-+// hcd->uses_new_polling = 1;
-+// hcd->poll_rh = 0;
-+#endif
-+ if (!hcd) {
-+ retval = -ENOMEM;
-+ goto error1;
-+ }
-+
-+ hcd->regs = otg_dev->os_dep.base;
-+
-+ if (fiq_fix_enable)
-+ {
-+ volatile extern void *dwc_regs_base;
-+
-+ //Set the mphi periph to the required registers
-+ c_mphi_regs.base = otg_dev->os_dep.mphi_base;
-+ c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
-+ c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
-+ c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
-+ c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
-+
-+ dwc_regs_base = otg_dev->os_dep.base;
-+
-+ //Enable mphi peripheral
-+ writel((1<<31),c_mphi_regs.ctrl);
-+#ifdef DEBUG
-+ if (readl(c_mphi_regs.ctrl) & 0x80000000)
-+ DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n");
-+ else
-+ DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n");
-+#endif
-+ // Enable FIQ interrupt from USB peripheral
-+ enable_fiq(INTERRUPT_VC_USB);
-+ }
-+ /* Initialize the DWC OTG HCD. */
-+ dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
-+ if (!dwc_otg_hcd) {
-+ goto error2;
-+ }
-+ ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
-+ dwc_otg_hcd;
-+ otg_dev->hcd = dwc_otg_hcd;
-+
-+ if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
-+ goto error2;
-+ }
-+
-+ otg_dev->hcd->otg_dev = otg_dev;
-+ hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
-+ hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
-+#endif
-+ /* Don't support SG list at this point */
-+ hcd->self.sg_tablesize = 0;
-+#endif
-+ /*
-+ * Finish generic HCD initialization and start the HCD. This function
-+ * allocates the DMA buffer pool, registers the USB bus, requests the
-+ * IRQ line, and calls hcd_start method.
-+ */
-+#ifdef PLATFORM_INTERFACE
-+ retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED);
-+#else
-+ retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
-+#endif
-+ if (retval < 0) {
-+ goto error2;
-+ }
-+
-+ dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
-+ return 0;
-+
-+error2:
-+ usb_put_hcd(hcd);
-+error1:
-+ return retval;
-+}
-+
-+/**
-+ * Removes the HCD.
-+ * Frees memory and resources associated with the HCD and deregisters the bus.
-+ */
-+void hcd_remove(dwc_bus_dev_t *_dev)
-+{
-+ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
-+ dwc_otg_hcd_t *dwc_otg_hcd;
-+ struct usb_hcd *hcd;
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
-+
-+ if (!otg_dev) {
-+ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
-+ return;
-+ }
-+
-+ dwc_otg_hcd = otg_dev->hcd;
-+
-+ if (!dwc_otg_hcd) {
-+ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
-+ return;
-+ }
-+
-+ hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
-+
-+ if (!hcd) {
-+ DWC_DEBUGPL(DBG_ANY,
-+ "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
-+ __func__);
-+ return;
-+ }
-+ usb_remove_hcd(hcd);
-+ dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
-+ dwc_otg_hcd_remove(dwc_otg_hcd);
-+ usb_put_hcd(hcd);
-+}
-+
-+/* =========================================================================
-+ * Linux HC Driver Functions
-+ * ========================================================================= */
-+
-+/** Initializes the DWC_otg controller and its root hub and prepares it for host
-+ * mode operation. Activates the root port. Returns 0 on success and a negative
-+ * error code on failure. */
-+int hcd_start(struct usb_hcd *hcd)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+ struct usb_bus *bus;
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
-+ bus = hcd_to_bus(hcd);
-+
-+ hcd->state = HC_STATE_RUNNING;
-+ if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
-+ return 0;
-+ }
-+
-+ /* Initialize and connect root hub if one is not already attached */
-+ if (bus->root_hub) {
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
-+ /* Inform the HUB driver to resume. */
-+ usb_hcd_resume_root_hub(hcd);
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
-+ * stopped.
-+ */
-+void hcd_stop(struct usb_hcd *hcd)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+
-+ dwc_otg_hcd_stop(dwc_otg_hcd);
-+}
-+
-+/** Returns the current frame number. */
-+static int get_frame_number(struct usb_hcd *hcd)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+
-+ return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
-+}
-+
-+#ifdef DEBUG
-+static void dump_urb_info(struct urb *urb, char *fn_name)
-+{
-+ DWC_PRINTF("%s, urb %p\n", fn_name, urb);
-+ DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
-+ DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
-+ (usb_pipein(urb->pipe) ? "IN" : "OUT"));
-+ DWC_PRINTF(" Endpoint type: %s\n", ( {
-+ char *pipetype;
-+ switch (usb_pipetype(urb->pipe)) {
-+case PIPE_CONTROL:
-+pipetype = "CONTROL"; break; case PIPE_BULK:
-+pipetype = "BULK"; break; case PIPE_INTERRUPT:
-+pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
-+pipetype = "ISOCHRONOUS"; break; default:
-+ pipetype = "UNKNOWN"; break;};
-+ pipetype;}
-+ )) ;
-+ DWC_PRINTF(" Speed: %s\n", ( {
-+ char *speed; switch (urb->dev->speed) {
-+case USB_SPEED_HIGH:
-+speed = "HIGH"; break; case USB_SPEED_FULL:
-+speed = "FULL"; break; case USB_SPEED_LOW:
-+speed = "LOW"; break; default:
-+ speed = "UNKNOWN"; break;};
-+ speed;}
-+ )) ;
-+ DWC_PRINTF(" Max packet size: %d\n",
-+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
-+ DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
-+ DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
-+ urb->transfer_buffer, (void *)urb->transfer_dma);
-+ DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
-+ urb->setup_packet, (void *)urb->setup_dma);
-+ DWC_PRINTF(" Interval: %d\n", urb->interval);
-+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-+ int i;
-+ for (i = 0; i < urb->number_of_packets; i++) {
-+ DWC_PRINTF(" ISO Desc %d:\n", i);
-+ DWC_PRINTF(" offset: %d, length %d\n",
-+ urb->iso_frame_desc[i].offset,
-+ urb->iso_frame_desc[i].length);
-+ }
-+ }
-+}
-+#endif
-+
-+/** Starts processing a USB transfer request specified by a USB Request Block
-+ * (URB). mem_flags indicates the type of memory allocation to use while
-+ * processing this URB. */
-+static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ struct usb_host_endpoint *ep,
-+#endif
-+ struct urb *urb, gfp_t mem_flags)
-+{
-+ int retval = 0;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
-+ struct usb_host_endpoint *ep = urb->ep;
-+#endif
-+ dwc_irqflags_t irqflags;
-+ void **ref_ep_hcpriv = &ep->hcpriv;
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+ dwc_otg_hcd_urb_t *dwc_otg_urb;
-+ int i;
-+ int alloc_bandwidth = 0;
-+ uint8_t ep_type = 0;
-+ uint32_t flags = 0;
-+ void *buf;
-+
-+#ifdef DEBUG
-+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
-+ dump_urb_info(urb, "dwc_otg_urb_enqueue");
-+ }
-+#endif
-+
-+ if (!urb->transfer_buffer && urb->transfer_buffer_length)
-+ return -EINVAL;
-+
-+ if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-+ || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
-+ if (!dwc_otg_hcd_is_bandwidth_allocated
-+ (dwc_otg_hcd, ref_ep_hcpriv)) {
-+ alloc_bandwidth = 1;
-+ }
-+ }
-+
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_CONTROL:
-+ ep_type = USB_ENDPOINT_XFER_CONTROL;
-+ break;
-+ case PIPE_ISOCHRONOUS:
-+ ep_type = USB_ENDPOINT_XFER_ISOC;
-+ break;
-+ case PIPE_BULK:
-+ ep_type = USB_ENDPOINT_XFER_BULK;
-+ break;
-+ case PIPE_INTERRUPT:
-+ ep_type = USB_ENDPOINT_XFER_INT;
-+ break;
-+ default:
-+ DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
-+ }
-+
-+ /* # of packets is often 0 - do we really need to call this then? */
-+ dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
-+ urb->number_of_packets,
-+ mem_flags == GFP_ATOMIC ? 1 : 0);
-+
-+ if(dwc_otg_urb == NULL)
-+ return -ENOMEM;
-+
-+ if (!dwc_otg_urb && urb->number_of_packets)
-+ return -ENOMEM;
-+
-+ dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
-+ usb_pipeendpoint(urb->pipe), ep_type,
-+ usb_pipein(urb->pipe),
-+ usb_maxpacket(urb->dev, urb->pipe,
-+ !(usb_pipein(urb->pipe))));
-+
-+ buf = urb->transfer_buffer;
-+ if (hcd->self.uses_dma) {
-+ /*
-+ * Calculate virtual address from physical address,
-+ * because some class driver may not fill transfer_buffer.
-+ * In Buffer DMA mode virual address is used,
-+ * when handling non DWORD aligned buffers.
-+ */
-+ //buf = phys_to_virt(urb->transfer_dma);
-+ // DMA addresses are bus addresses not physical addresses!
-+ buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
-+ }
-+
-+ if (!(urb->transfer_flags & URB_NO_INTERRUPT))
-+ flags |= URB_GIVEBACK_ASAP;
-+ if (urb->transfer_flags & URB_ZERO_PACKET)
-+ flags |= URB_SEND_ZERO_PACKET;
-+
-+ dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
-+ urb->transfer_dma,
-+ urb->transfer_buffer_length,
-+ urb->setup_packet,
-+ urb->setup_dma, flags, urb->interval);
-+
-+ for (i = 0; i < urb->number_of_packets; ++i) {
-+ dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
-+ urb->
-+ iso_frame_desc[i].offset,
-+ urb->
-+ iso_frame_desc[i].length);
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
-+ urb->hcpriv = dwc_otg_urb;
-+#if USB_URB_EP_LINKING
-+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
-+ if (0 == retval)
-+#endif
-+ {
-+ retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
-+ /*(dwc_otg_qh_t **)*/
-+ ref_ep_hcpriv, 1);
-+ if (0 == retval) {
-+ if (alloc_bandwidth) {
-+ allocate_bus_bandwidth(hcd,
-+ dwc_otg_hcd_get_ep_bandwidth(
-+ dwc_otg_hcd, *ref_ep_hcpriv),
-+ urb);
-+ }
-+ } else {
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
-+#if USB_URB_EP_LINKING
-+ usb_hcd_unlink_urb_from_ep(hcd, urb);
-+#endif
-+ DWC_FREE(dwc_otg_urb);
-+ urb->hcpriv = NULL;
-+ if (retval == -DWC_E_NO_DEVICE)
-+ retval = -ENODEV;
-+ }
-+ }
-+#if USB_URB_EP_LINKING
-+ else
-+ {
-+ DWC_FREE(dwc_otg_urb);
-+ urb->hcpriv = NULL;
-+ }
-+#endif
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
-+ return retval;
-+}
-+
-+/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
-+ * success. */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
-+#else
-+static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
-+#endif
-+{
-+ dwc_irqflags_t flags;
-+ dwc_otg_hcd_t *dwc_otg_hcd;
-+ int rc;
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
-+
-+ dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+
-+#ifdef DEBUG
-+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
-+ dump_urb_info(urb, "dwc_otg_urb_dequeue");
-+ }
-+#endif
-+
-+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
-+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
-+ if (0 == rc) {
-+ if(urb->hcpriv != NULL) {
-+ dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
-+ (dwc_otg_hcd_urb_t *)urb->hcpriv);
-+
-+ DWC_FREE(urb->hcpriv);
-+ urb->hcpriv = NULL;
-+ }
-+ }
-+
-+ if (0 == rc) {
-+ /* Higher layer software sets URB status. */
-+#if USB_URB_EP_LINKING
-+ usb_hcd_unlink_urb_from_ep(hcd, urb);
-+#endif
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
-+
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ usb_hcd_giveback_urb(hcd, urb);
-+#else
-+ usb_hcd_giveback_urb(hcd, urb, status);
-+#endif
-+ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
-+ DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
-+ DWC_PRINTF(" 1urb->status = %d\n", urb->status);
-+ }
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
-+ } else {
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
-+ rc);
-+ }
-+
-+ return rc;
-+}
-+
-+/* Frees resources in the DWC_otg controller related to a given endpoint. Also
-+ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
-+ * must already be dequeued. */
-+static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+
-+ DWC_DEBUGPL(DBG_HCD,
-+ "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
-+ "endpoint=%d\n", ep->desc.bEndpointAddress,
-+ dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
-+ dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
-+ ep->hcpriv = NULL;
-+}
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
-+/* Resets endpoint specific parameter values, in current version used to reset
-+ * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
-+static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
-+{
-+ dwc_irqflags_t flags;
-+ struct usb_device *udev = NULL;
-+ int epnum = usb_endpoint_num(&ep->desc);
-+ int is_out = usb_endpoint_dir_out(&ep->desc);
-+ int is_control = usb_endpoint_xfer_control(&ep->desc);
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+ struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep);
-+
-+ if (dev)
-+ udev = to_usb_device(dev);
-+ else
-+ return;
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
-+
-+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
-+ usb_settoggle(udev, epnum, is_out, 0);
-+ if (is_control)
-+ usb_settoggle(udev, epnum, !is_out, 0);
-+
-+ if (ep->hcpriv) {
-+ dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
-+ }
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
-+}
-+#endif
-+
-+/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
-+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
-+ * interrupt.
-+ *
-+ * This function is called by the USB core when an interrupt occurs */
-+static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+ int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
-+ if (retval != 0) {
-+ S3C2410X_CLEAR_EINTPEND();
-+ }
-+ return IRQ_RETVAL(retval);
-+}
-+
-+/** Creates Status Change bitmap for the root hub and root port. The bitmap is
-+ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
-+ * is the status change indicator for the single root port. Returns 1 if either
-+ * change indicator is 1, otherwise returns 0. */
-+int hub_status_data(struct usb_hcd *hcd, char *buf)
-+{
-+ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
-+
-+ buf[0] = 0;
-+ buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
-+
-+ return (buf[0] != 0);
-+}
-+
-+/** Handles hub class-specific requests. */
-+int hub_control(struct usb_hcd *hcd,
-+ u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
-+{
-+ int retval;
-+
-+ retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
-+ typeReq, wValue, wIndex, buf, wLength);
-+
-+ switch (retval) {
-+ case -DWC_E_INVALID:
-+ retval = -EINVAL;
-+ break;
-+ }
-+
-+ return retval;
-+}
-+
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,959 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
-+ * $Revision: #44 $
-+ * $Date: 2011/10/26 $
-+ * $Change: 1873028 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_DEVICE_ONLY
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the functions to manage Queue Heads and Queue
-+ * Transfer Descriptors.
-+ */
-+
-+#include "dwc_otg_hcd.h"
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_mphi_fix.h"
-+
-+extern bool microframe_schedule;
-+
-+/**
-+ * Free each QTD in the QH's QTD-list then free the QH. QH should already be
-+ * removed from a list. QTD list should already be empty if called from URB
-+ * Dequeue.
-+ *
-+ * @param hcd HCD instance.
-+ * @param qh The QH to free.
-+ */
-+void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ dwc_otg_qtd_t *qtd, *qtd_tmp;
-+
-+ /* Free each QTD in the QTD list */
-+ DWC_SPINLOCK(hcd->lock);
-+ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
-+ DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
-+ dwc_otg_hcd_qtd_free(qtd);
-+ }
-+
-+ if (hcd->core_if->dma_desc_enable) {
-+ dwc_otg_hcd_qh_free_ddma(hcd, qh);
-+ } else if (qh->dw_align_buf) {
-+ uint32_t buf_size;
-+ if (qh->ep_type == UE_ISOCHRONOUS) {
-+ buf_size = 4096;
-+ } else {
-+ buf_size = hcd->core_if->core_params->max_transfer_size;
-+ }
-+ DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
-+ }
-+
-+ DWC_FREE(qh);
-+ DWC_SPINUNLOCK(hcd->lock);
-+ return;
-+}
-+
-+#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
-+#define HS_HOST_DELAY 5 /* nanoseconds */
-+#define FS_LS_HOST_DELAY 1000 /* nanoseconds */
-+#define HUB_LS_SETUP 333 /* nanoseconds */
-+#define NS_TO_US(ns) ((ns + 500) / 1000)
-+ /* convert & round nanoseconds to microseconds */
-+
-+static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
-+{
-+ unsigned long retval;
-+
-+ switch (speed) {
-+ case USB_SPEED_HIGH:
-+ if (is_isoc) {
-+ retval =
-+ ((38 * 8 * 2083) +
-+ (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
-+ HS_HOST_DELAY;
-+ } else {
-+ retval =
-+ ((55 * 8 * 2083) +
-+ (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
-+ HS_HOST_DELAY;
-+ }
-+ break;
-+ case USB_SPEED_FULL:
-+ if (is_isoc) {
-+ retval =
-+ (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
-+ if (is_in) {
-+ retval = 7268 + FS_LS_HOST_DELAY + retval;
-+ } else {
-+ retval = 6265 + FS_LS_HOST_DELAY + retval;
-+ }
-+ } else {
-+ retval =
-+ (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
-+ retval = 9107 + FS_LS_HOST_DELAY + retval;
-+ }
-+ break;
-+ case USB_SPEED_LOW:
-+ if (is_in) {
-+ retval =
-+ (67667 * (31 + 10 * BitStuffTime(bytecount))) /
-+ 1000;
-+ retval =
-+ 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
-+ retval;
-+ } else {
-+ retval =
-+ (66700 * (31 + 10 * BitStuffTime(bytecount))) /
-+ 1000;
-+ retval =
-+ 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
-+ retval;
-+ }
-+ break;
-+ default:
-+ DWC_WARN("Unknown device speed\n");
-+ retval = -1;
-+ }
-+
-+ return NS_TO_US(retval);
-+}
-+
-+/**
-+ * Initializes a QH structure.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh The QH to init.
-+ * @param urb Holds the information about the device/endpoint that we need
-+ * to initialize the QH.
-+ */
-+#define SCHEDULE_SLOP 10
-+void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
-+{
-+ char *speed, *type;
-+ int dev_speed;
-+ uint32_t hub_addr, hub_port;
-+
-+ dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
-+
-+ /* Initialize QH */
-+ qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
-+ qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
-+
-+ qh->data_toggle = DWC_OTG_HC_PID_DATA0;
-+ qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
-+ DWC_CIRCLEQ_INIT(&qh->qtd_list);
-+ DWC_LIST_INIT(&qh->qh_list_entry);
-+ qh->channel = NULL;
-+
-+ /* FS/LS Enpoint on HS Hub
-+ * NOT virtual root hub */
-+ dev_speed = hcd->fops->speed(hcd, urb->priv);
-+
-+ hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
-+ qh->do_split = 0;
-+ if (microframe_schedule)
-+ qh->speed = dev_speed;
-+
-+ qh->nak_frame = 0xffff;
-+
-+ if (((dev_speed == USB_SPEED_LOW) ||
-+ (dev_speed == USB_SPEED_FULL)) &&
-+ (hub_addr != 0 && hub_addr != 1)) {
-+ DWC_DEBUGPL(DBG_HCD,
-+ "QH init: EP %d: TT found at hub addr %d, for port %d\n",
-+ dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
-+ hub_port);
-+ qh->do_split = 1;
-+ qh->skip_count = 0;
-+ }
-+
-+ if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
-+ /* Compute scheduling parameters once and save them. */
-+ hprt0_data_t hprt;
-+
-+ /** @todo Account for split transfers in the bus time. */
-+ int bytecount =
-+ dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
-+
-+ qh->usecs =
-+ calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
-+ qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
-+ bytecount);
-+ /* Start in a slightly future (micro)frame. */
-+ qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
-+ SCHEDULE_SLOP);
-+ qh->interval = urb->interval;
-+
-+#if 0
-+ /* Increase interrupt polling rate for debugging. */
-+ if (qh->ep_type == UE_INTERRUPT) {
-+ qh->interval = 8;
-+ }
-+#endif
-+ hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
-+ if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
-+ ((dev_speed == USB_SPEED_LOW) ||
-+ (dev_speed == USB_SPEED_FULL))) {
-+ qh->interval *= 8;
-+ qh->sched_frame |= 0x7;
-+ qh->start_split_frame = qh->sched_frame;
-+ }
-+
-+ }
-+
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
-+ dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
-+ dwc_otg_hcd_get_ep_num(&urb->pipe_info),
-+ dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
-+ switch (dev_speed) {
-+ case USB_SPEED_LOW:
-+ qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
-+ speed = "low";
-+ break;
-+ case USB_SPEED_FULL:
-+ qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
-+ speed = "full";
-+ break;
-+ case USB_SPEED_HIGH:
-+ qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
-+ speed = "high";
-+ break;
-+ default:
-+ speed = "?";
-+ break;
-+ }
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
-+
-+ switch (qh->ep_type) {
-+ case UE_ISOCHRONOUS:
-+ type = "isochronous";
-+ break;
-+ case UE_INTERRUPT:
-+ type = "interrupt";
-+ break;
-+ case UE_CONTROL:
-+ type = "control";
-+ break;
-+ case UE_BULK:
-+ type = "bulk";
-+ break;
-+ default:
-+ type = "?";
-+ break;
-+ }
-+
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
-+
-+#ifdef DEBUG
-+ if (qh->ep_type == UE_INTERRUPT) {
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
-+ qh->usecs);
-+ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
-+ qh->interval);
-+ }
-+#endif
-+
-+}
-+
-+/**
-+ * This function allocates and initializes a QH.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param urb Holds the information about the device/endpoint that we need
-+ * to initialize the QH.
-+ * @param atomic_alloc Flag to do atomic allocation if needed
-+ *
-+ * @return Returns pointer to the newly allocated QH, or NULL on error. */
-+dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
-+ dwc_otg_hcd_urb_t * urb, int atomic_alloc)
-+{
-+ dwc_otg_qh_t *qh;
-+
-+ /* Allocate memory */
-+ /** @todo add memflags argument */
-+ qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
-+ if (qh == NULL) {
-+ DWC_ERROR("qh allocation failed");
-+ return NULL;
-+ }
-+
-+ qh_init(hcd, qh, urb);
-+
-+ if (hcd->core_if->dma_desc_enable
-+ && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
-+ dwc_otg_hcd_qh_free(hcd, qh);
-+ return NULL;
-+ }
-+
-+ return qh;
-+}
-+
-+/* microframe_schedule=0 start */
-+
-+/**
-+ * Checks that a channel is available for a periodic transfer.
-+ *
-+ * @return 0 if successful, negative error code otherise.
-+ */
-+static int periodic_channel_available(dwc_otg_hcd_t * hcd)
-+{
-+ /*
-+ * Currently assuming that there is a dedicated host channnel for each
-+ * periodic transaction plus at least one host channel for
-+ * non-periodic transactions.
-+ */
-+ int status;
-+ int num_channels;
-+
-+ num_channels = hcd->core_if->core_params->host_channels;
-+ if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
-+ && (hcd->periodic_channels < num_channels - 1)) {
-+ status = 0;
-+ } else {
-+ DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
-+ __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE
-+ status = -DWC_E_NO_SPACE;
-+ }
-+
-+ return status;
-+}
-+
-+/**
-+ * Checks that there is sufficient bandwidth for the specified QH in the
-+ * periodic schedule. For simplicity, this calculation assumes that all the
-+ * transfers in the periodic schedule may occur in the same (micro)frame.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh QH containing periodic bandwidth required.
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ int status;
-+ int16_t max_claimed_usecs;
-+
-+ status = 0;
-+
-+ if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
-+ /*
-+ * High speed mode.
-+ * Max periodic usecs is 80% x 125 usec = 100 usec.
-+ */
-+
-+ max_claimed_usecs = 100 - qh->usecs;
-+ } else {
-+ /*
-+ * Full speed mode.
-+ * Max periodic usecs is 90% x 1000 usec = 900 usec.
-+ */
-+ max_claimed_usecs = 900 - qh->usecs;
-+ }
-+
-+ if (hcd->periodic_usecs > max_claimed_usecs) {
-+ DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE
-+ status = -DWC_E_NO_SPACE;
-+ }
-+
-+ return status;
-+}
-+
-+/* microframe_schedule=0 end */
-+
-+/**
-+ * Microframe scheduler
-+ * track the total use in hcd->frame_usecs
-+ * keep each qh use in qh->frame_usecs
-+ * when surrendering the qh then donate the time back
-+ */
-+const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
-+
-+/*
-+ * called from dwc_otg_hcd.c:dwc_otg_hcd_init
-+ */
-+int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
-+{
-+ int i;
-+ for (i=0; i<8; i++) {
-+ _hcd->frame_usecs[i] = max_uframe_usecs[i];
-+ }
-+ return 0;
-+}
-+
-+static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
-+{
-+ int i;
-+ unsigned short utime;
-+ int t_left;
-+ int ret;
-+ int done;
-+
-+ ret = -1;
-+ utime = _qh->usecs;
-+ t_left = utime;
-+ i = 0;
-+ done = 0;
-+ while (done == 0) {
-+ /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
-+ if (utime <= _hcd->frame_usecs[i]) {
-+ _hcd->frame_usecs[i] -= utime;
-+ _qh->frame_usecs[i] += utime;
-+ t_left -= utime;
-+ ret = i;
-+ done = 1;
-+ return ret;
-+ } else {
-+ i++;
-+ if (i == 8) {
-+ done = 1;
-+ ret = -1;
-+ }
-+ }
-+ }
-+ return ret;
-+ }
-+
-+/*
-+ * use this for FS apps that can span multiple uframes
-+ */
-+static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
-+{
-+ int i;
-+ int j;
-+ unsigned short utime;
-+ int t_left;
-+ int ret;
-+ int done;
-+ unsigned short xtime;
-+
-+ ret = -1;
-+ utime = _qh->usecs;
-+ t_left = utime;
-+ i = 0;
-+ done = 0;
-+loop:
-+ while (done == 0) {
-+ if(_hcd->frame_usecs[i] <= 0) {
-+ i++;
-+ if (i == 8) {
-+ done = 1;
-+ ret = -1;
-+ }
-+ goto loop;
-+ }
-+
-+ /*
-+ * we need n consecutive slots
-+ * so use j as a start slot j plus j+1 must be enough time (for now)
-+ */
-+ xtime= _hcd->frame_usecs[i];
-+ for (j = i+1 ; j < 8 ; j++ ) {
-+ /*
-+ * if we add this frame remaining time to xtime we may
-+ * be OK, if not we need to test j for a complete frame
-+ */
-+ if ((xtime+_hcd->frame_usecs[j]) < utime) {
-+ if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
-+ j = 8;
-+ ret = -1;
-+ continue;
-+ }
-+ }
-+ if (xtime >= utime) {
-+ ret = i;
-+ j = 8; /* stop loop with a good value ret */
-+ continue;
-+ }
-+ /* add the frame time to x time */
-+ xtime += _hcd->frame_usecs[j];
-+ /* we must have a fully available next frame or break */
-+ if ((xtime < utime)
-+ && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
-+ ret = -1;
-+ j = 8; /* stop loop with a bad value ret */
-+ continue;
-+ }
-+ }
-+ if (ret >= 0) {
-+ t_left = utime;
-+ for (j = i; (t_left>0) && (j < 8); j++ ) {
-+ t_left -= _hcd->frame_usecs[j];
-+ if ( t_left <= 0 ) {
-+ _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
-+ _hcd->frame_usecs[j]= -t_left;
-+ ret = i;
-+ done = 1;
-+ } else {
-+ _qh->frame_usecs[j] += _hcd->frame_usecs[j];
-+ _hcd->frame_usecs[j] = 0;
-+ }
-+ }
-+ } else {
-+ i++;
-+ if (i == 8) {
-+ done = 1;
-+ ret = -1;
-+ }
-+ }
-+ }
-+ return ret;
-+}
-+
-+static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
-+{
-+ int ret;
-+ ret = -1;
-+
-+ if (_qh->speed == USB_SPEED_HIGH) {
-+ /* if this is a hs transaction we need a full frame */
-+ ret = find_single_uframe(_hcd, _qh);
-+ } else {
-+ /* if this is a fs transaction we may need a sequence of frames */
-+ ret = find_multi_uframe(_hcd, _qh);
-+ }
-+ return ret;
-+}
-+
-+/**
-+ * Checks that the max transfer size allowed in a host channel is large enough
-+ * to handle the maximum data transfer in a single (micro)frame for a periodic
-+ * transfer.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh QH for a periodic endpoint.
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ int status;
-+ uint32_t max_xfer_size;
-+ uint32_t max_channel_xfer_size;
-+
-+ status = 0;
-+
-+ max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
-+ max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
-+
-+ if (max_xfer_size > max_channel_xfer_size) {
-+ DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
-+ __func__, max_xfer_size, max_channel_xfer_size); //NOTICE
-+ status = -DWC_E_NO_SPACE;
-+ }
-+
-+ return status;
-+}
-+
-+
-+extern int g_next_sched_frame, g_np_count, g_np_sent;
-+
-+/**
-+ * Schedules an interrupt or isochronous transfer in the periodic schedule.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh QH for the periodic transfer. The QH should already contain the
-+ * scheduling information.
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ int status = 0;
-+
-+ if (microframe_schedule) {
-+ int frame;
-+ status = find_uframe(hcd, qh);
-+ frame = -1;
-+ if (status == 0) {
-+ frame = 7;
-+ } else {
-+ if (status > 0 )
-+ frame = status-1;
-+ }
-+
-+ /* Set the new frame up */
-+ if (frame > -1) {
-+ qh->sched_frame &= ~0x7;
-+ qh->sched_frame |= (frame & 7);
-+ }
-+
-+ if (status != -1)
-+ status = 0;
-+ } else {
-+ status = periodic_channel_available(hcd);
-+ if (status) {
-+ DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
-+ return status;
-+ }
-+
-+ status = check_periodic_bandwidth(hcd, qh);
-+ }
-+ if (status) {
-+ DWC_INFO("%s: Insufficient periodic bandwidth for "
-+ "periodic transfer.\n", __func__);
-+ return status;
-+ }
-+ status = check_max_xfer_size(hcd, qh);
-+ if (status) {
-+ DWC_INFO("%s: Channel max transfer size too small "
-+ "for periodic transfer.\n", __func__);
-+ return status;
-+ }
-+
-+ if (hcd->core_if->dma_desc_enable) {
-+ /* Don't rely on SOF and start in ready schedule */
-+ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
-+ }
-+ else {
-+ if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame))
-+ {
-+ g_next_sched_frame = qh->sched_frame;
-+
-+ }
-+ /* Always start in the inactive schedule. */
-+ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
-+ }
-+
-+ if (!microframe_schedule) {
-+ /* Reserve the periodic channel. */
-+ hcd->periodic_channels++;
-+ }
-+
-+ /* Update claimed usecs per (micro)frame. */
-+ hcd->periodic_usecs += qh->usecs;
-+
-+ return status;
-+}
-+
-+
-+/**
-+ * This function adds a QH to either the non periodic or periodic schedule if
-+ * it is not already in the schedule. If the QH is already in the schedule, no
-+ * action is taken.
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ int status = 0;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
-+ /* QH already in a schedule. */
-+ return status;
-+ }
-+
-+ /* Add the new QH to the appropriate schedule */
-+ if (dwc_qh_is_non_per(qh)) {
-+ /* Always start in the inactive schedule. */
-+ DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
-+ &qh->qh_list_entry);
-+ g_np_count++;
-+ } else {
-+ status = schedule_periodic(hcd, qh);
-+ if ( !hcd->periodic_qh_count ) {
-+ intr_mask.b.sofintr = 1;
-+ DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
-+ intr_mask.d32, intr_mask.d32);
-+ }
-+ hcd->periodic_qh_count++;
-+ }
-+
-+ return status;
-+}
-+
-+/**
-+ * Removes an interrupt or isochronous transfer from the periodic schedule.
-+ *
-+ * @param hcd The HCD state structure for the DWC OTG controller.
-+ * @param qh QH for the periodic transfer.
-+ */
-+static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ int i;
-+ DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
-+
-+ /* Update claimed usecs per (micro)frame. */
-+ hcd->periodic_usecs -= qh->usecs;
-+
-+ if (!microframe_schedule) {
-+ /* Release the periodic channel reservation. */
-+ hcd->periodic_channels--;
-+ } else {
-+ for (i = 0; i < 8; i++) {
-+ hcd->frame_usecs[i] += qh->frame_usecs[i];
-+ qh->frame_usecs[i] = 0;
-+ }
-+ }
-+}
-+
-+/**
-+ * Removes a QH from either the non-periodic or periodic schedule. Memory is
-+ * not freed.
-+ *
-+ * @param hcd The HCD state structure.
-+ * @param qh QH to remove from schedule. */
-+void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
-+{
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
-+ /* QH is not in a schedule. */
-+ return;
-+ }
-+
-+ if (dwc_qh_is_non_per(qh)) {
-+ if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
-+ hcd->non_periodic_qh_ptr =
-+ hcd->non_periodic_qh_ptr->next;
-+ }
-+ DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
-+
-+ // If we've removed the last non-periodic entry then there are none left!
-+ g_np_count = g_np_sent;
-+ } else {
-+ deschedule_periodic(hcd, qh);
-+ hcd->periodic_qh_count--;
-+ if( !hcd->periodic_qh_count ) {
-+ intr_mask.b.sofintr = 1;
-+ DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+ }
-+ }
-+}
-+
-+/**
-+ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
-+ * non-periodic schedule. The QH is added to the inactive non-periodic
-+ * schedule if any QTDs are still attached to the QH.
-+ *
-+ * For periodic QHs, the QH is removed from the periodic queued schedule. If
-+ * there are any QTDs still attached to the QH, the QH is added to either the
-+ * periodic inactive schedule or the periodic ready schedule and its next
-+ * scheduled frame is calculated. The QH is placed in the ready schedule if
-+ * the scheduled frame has been reached already. Otherwise it's placed in the
-+ * inactive schedule. If there are no QTDs attached to the QH, the QH is
-+ * completely removed from the periodic schedule.
-+ */
-+void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
-+ int sched_next_periodic_split)
-+{
-+ if (dwc_qh_is_non_per(qh)) {
-+
-+ dwc_otg_qh_t *qh_tmp;
-+ dwc_list_link_t *qh_list;
-+ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive)
-+ {
-+ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry);
-+ if(qh_tmp == qh)
-+ {
-+ /*
-+ * FIQ is being disabled because this one nevers gets a np_count increment
-+ * This is still not absolutely correct, but it should fix itself with
-+ * just an unnecessary extra interrupt
-+ */
-+ g_np_sent = g_np_count;
-+ }
-+ }
-+
-+
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+ if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
-+ /* Add back to inactive non-periodic schedule. */
-+ dwc_otg_hcd_qh_add(hcd, qh);
-+ }
-+ } else {
-+ uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
-+
-+ if (qh->do_split) {
-+ /* Schedule the next continuing periodic split transfer */
-+ if (sched_next_periodic_split) {
-+
-+ qh->sched_frame = frame_number;
-+
-+ if (dwc_frame_num_le(frame_number,
-+ dwc_frame_num_inc
-+ (qh->start_split_frame,
-+ 1))) {
-+ /*
-+ * Allow one frame to elapse after start
-+ * split microframe before scheduling
-+ * complete split, but DONT if we are
-+ * doing the next start split in the
-+ * same frame for an ISOC out.
-+ */
-+ if ((qh->ep_type != UE_ISOCHRONOUS) ||
-+ (qh->ep_is_in != 0)) {
-+ qh->sched_frame =
-+ dwc_frame_num_inc(qh->sched_frame, 1);
-+ }
-+ }
-+ } else {
-+ qh->sched_frame =
-+ dwc_frame_num_inc(qh->start_split_frame,
-+ qh->interval);
-+ if (dwc_frame_num_le
-+ (qh->sched_frame, frame_number)) {
-+ qh->sched_frame = frame_number;
-+ }
-+ qh->sched_frame |= 0x7;
-+ qh->start_split_frame = qh->sched_frame;
-+ }
-+ } else {
-+ qh->sched_frame =
-+ dwc_frame_num_inc(qh->sched_frame, qh->interval);
-+ if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
-+ qh->sched_frame = frame_number;
-+ }
-+ }
-+
-+ if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
-+ dwc_otg_hcd_qh_remove(hcd, qh);
-+ } else {
-+ /*
-+ * Remove from periodic_sched_queued and move to
-+ * appropriate queue.
-+ */
-+ if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
-+ (!microframe_schedule && qh->sched_frame == frame_number)) {
-+ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
-+ &qh->qh_list_entry);
-+ } else {
-+ if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame))
-+ {
-+ g_next_sched_frame = qh->sched_frame;
-+ }
-+
-+ DWC_LIST_MOVE_HEAD
-+ (&hcd->periodic_sched_inactive,
-+ &qh->qh_list_entry);
-+ }
-+ }
-+ }
-+}
-+
-+/**
-+ * This function allocates and initializes a QTD.
-+ *
-+ * @param urb The URB to create a QTD from. Each URB-QTD pair will end up
-+ * pointing to each other so each pair should have a unique correlation.
-+ * @param atomic_alloc Flag to do atomic alloc if needed
-+ *
-+ * @return Returns pointer to the newly allocated QTD, or NULL on error. */
-+dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
-+{
-+ dwc_otg_qtd_t *qtd;
-+
-+ qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
-+ if (qtd == NULL) {
-+ return NULL;
-+ }
-+
-+ dwc_otg_hcd_qtd_init(qtd, urb);
-+ return qtd;
-+}
-+
-+/**
-+ * Initializes a QTD structure.
-+ *
-+ * @param qtd The QTD to initialize.
-+ * @param urb The URB to use for initialization. */
-+void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
-+{
-+ dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
-+ qtd->urb = urb;
-+ if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
-+ /*
-+ * The only time the QTD data toggle is used is on the data
-+ * phase of control transfers. This phase always starts with
-+ * DATA1.
-+ */
-+ qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
-+ qtd->control_phase = DWC_OTG_CONTROL_SETUP;
-+ }
-+
-+ /* start split */
-+ qtd->complete_split = 0;
-+ qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
-+ qtd->isoc_split_offset = 0;
-+ qtd->in_process = 0;
-+
-+ /* Store the qtd ptr in the urb to reference what QTD. */
-+ urb->qtd = qtd;
-+ return;
-+}
-+
-+/**
-+ * This function adds a QTD to the QTD-list of a QH. It will find the correct
-+ * QH to place the QTD into. If it does not find a QH, then it will create a
-+ * new QH. If the QH to which the QTD is added is not currently scheduled, it
-+ * is placed into the proper schedule based on its EP type.
-+ * HCD lock must be held and interrupts must be disabled on entry
-+ *
-+ * @param[in] qtd The QTD to add
-+ * @param[in] hcd The DWC HCD structure
-+ * @param[out] qh out parameter to return queue head
-+ * @param atomic_alloc Flag to do atomic alloc if needed
-+ *
-+ * @return 0 if successful, negative error code otherwise.
-+ */
-+int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
-+ dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
-+{
-+ int retval = 0;
-+ dwc_otg_hcd_urb_t *urb = qtd->urb;
-+
-+ /*
-+ * Get the QH which holds the QTD-list to insert to. Create QH if it
-+ * doesn't exist.
-+ */
-+ if (*qh == NULL) {
-+ *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
-+ if (*qh == NULL) {
-+ retval = -DWC_E_NO_MEMORY;
-+ goto done;
-+ }
-+ }
-+ retval = dwc_otg_hcd_qh_add(hcd, *qh);
-+ if (retval == 0) {
-+ DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
-+ qtd_list_entry);
-+ qtd->qh = *qh;
-+ }
-+done:
-+
-+ return retval;
-+}
-+
-+#endif /* DWC_DEVICE_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,113 @@
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_dbg.h"
-+
-+void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name)
-+{
-+ DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n"
-+ "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n"
-+ "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n"
-+ "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n"
-+ "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n"
-+ "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n"
-+ "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n"
-+ "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n"
-+ "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n",
-+ function_name,
-+ gintsts.b.curmode,
-+ gintsts.b.modemismatch,
-+ gintsts.b.otgintr,
-+ gintsts.b.sofintr,
-+ gintsts.b.rxstsqlvl,
-+ gintsts.b.nptxfempty,
-+ gintsts.b.ginnakeff,
-+ gintsts.b.goutnakeff,
-+ gintsts.b.ulpickint,
-+ gintsts.b.i2cintr,
-+ gintsts.b.erlysuspend,
-+ gintsts.b.usbsuspend,
-+ gintsts.b.usbreset,
-+ gintsts.b.enumdone,
-+ gintsts.b.isooutdrop,
-+ gintsts.b.eopframe,
-+ gintsts.b.restoredone,
-+ gintsts.b.epmismatch,
-+ gintsts.b.inepint,
-+ gintsts.b.outepintr,
-+ gintsts.b.incomplisoin,
-+ gintsts.b.incomplisoout,
-+ gintsts.b.fetsusp,
-+ gintsts.b.resetdet,
-+ gintsts.b.portintr,
-+ gintsts.b.hcintr,
-+ gintsts.b.ptxfempty,
-+ gintsts.b.lpmtranrcvd,
-+ gintsts.b.conidstschng,
-+ gintsts.b.disconnect,
-+ gintsts.b.sessreqintr,
-+ gintsts.b.wkupintr);
-+ return;
-+}
-+
-+void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name)
-+{
-+ DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n"
-+ "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n"
-+ "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n"
-+ "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n"
-+ "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n"
-+ "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n"
-+ "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n"
-+ "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n"
-+ "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n",
-+ function_name,
-+ gintmsk.b.modemismatch,
-+ gintmsk.b.otgintr,
-+ gintmsk.b.sofintr,
-+ gintmsk.b.rxstsqlvl,
-+ gintmsk.b.nptxfempty,
-+ gintmsk.b.ginnakeff,
-+ gintmsk.b.goutnakeff,
-+ gintmsk.b.ulpickint,
-+ gintmsk.b.i2cintr,
-+ gintmsk.b.erlysuspend,
-+ gintmsk.b.usbsuspend,
-+ gintmsk.b.usbreset,
-+ gintmsk.b.enumdone,
-+ gintmsk.b.isooutdrop,
-+ gintmsk.b.eopframe,
-+ gintmsk.b.restoredone,
-+ gintmsk.b.epmismatch,
-+ gintmsk.b.inepintr,
-+ gintmsk.b.outepintr,
-+ gintmsk.b.incomplisoin,
-+ gintmsk.b.incomplisoout,
-+ gintmsk.b.fetsusp,
-+ gintmsk.b.resetdet,
-+ gintmsk.b.portintr,
-+ gintmsk.b.hcintr,
-+ gintmsk.b.ptxfempty,
-+ gintmsk.b.lpmtranrcvd,
-+ gintmsk.b.conidstschng,
-+ gintmsk.b.disconnect,
-+ gintmsk.b.sessreqintr,
-+ gintmsk.b.wkupintr);
-+ return;
-+}
-+
-+void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name)
-+{
-+ DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n"
-+ "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n"
-+ "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n"
-+ "mvic: %1i\n",
-+ function_name,
-+ gotgint.b.sesenddet,
-+ gotgint.b.sesreqsucstschng,
-+ gotgint.b.hstnegsucstschng,
-+ gotgint.b.hstnegdet,
-+ gotgint.b.adevtoutchng,
-+ gotgint.b.debdone,
-+ gotgint.b.mvic);
-+
-+ return;
-+}
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,48 @@
-+#ifndef __DWC_OTG_MPHI_FIX_H__
-+#define __DWC_OTG_MPHI_FIX_H__
-+#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_))
-+#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_))
-+
-+typedef struct {
-+ volatile void* base;
-+ volatile void* ctrl;
-+ volatile void* outdda;
-+ volatile void* outddb;
-+ volatile void* intstat;
-+} mphi_regs_t;
-+
-+void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name);
-+void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name);
-+void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name);
-+
-+extern gintsts_data_t gintsts_saved;
-+
-+#ifdef DEBUG
-+#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__)
-+#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__)
-+#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__)
-+
-+#else
-+#define DWC_DBG_PRINT_CORE_INT(_arg_)
-+#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_)
-+#define DWC_DBG_PRINT_OTG_INT(_arg_)
-+
-+#endif
-+
-+typedef enum {
-+ FIQDBG_SCHED = (1 << 0),
-+ FIQDBG_INT = (1 << 1),
-+ FIQDBG_ERR = (1 << 2),
-+ FIQDBG_PORTHUB = (1 << 3),
-+} FIQDBG_T;
-+
-+void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...);
-+#ifdef FIQ_DEBUG
-+#define fiq_print _fiq_print
-+#else
-+#define fiq_print(x, y, ...)
-+#endif
-+
-+extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable;
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,188 @@
-+#ifndef _DWC_OS_DEP_H_
-+#define _DWC_OS_DEP_H_
-+
-+/**
-+ * @file
-+ *
-+ * This file contains OS dependent structures.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/errno.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/ctype.h>
-+#include <linux/string.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/jiffies.h>
-+#include <linux/delay.h>
-+#include <linux/timer.h>
-+#include <linux/workqueue.h>
-+#include <linux/stat.h>
-+#include <linux/pci.h>
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-+# include <linux/irq.h>
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
-+# include <linux/usb/ch9.h>
-+#else
-+# include <linux/usb_ch9.h>
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+# include <linux/usb/gadget.h>
-+#else
-+# include <linux/usb_gadget.h>
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-+# include <asm/irq.h>
-+#endif
-+
-+#ifdef PCI_INTERFACE
-+# include <asm/io.h>
-+#endif
-+
-+#ifdef LM_INTERFACE
-+# include <asm/unaligned.h>
-+# include <asm/sizes.h>
-+# include <asm/param.h>
-+# include <asm/io.h>
-+# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30))
-+# include <asm/arch/hardware.h>
-+# include <asm/arch/lm.h>
-+# include <asm/arch/irqs.h>
-+# include <asm/arch/regs-irq.h>
-+# else
-+/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure -
-+ here we assume that the machine architecture provides definitions
-+ in its own header
-+*/
-+# include <mach/lm.h>
-+# include <mach/hardware.h>
-+# endif
-+#endif
-+
-+#ifdef PLATFORM_INTERFACE
-+#include <linux/platform_device.h>
-+#include <asm/mach/map.h>
-+#endif
-+
-+/** The OS page size */
-+#define DWC_OS_PAGE_SIZE PAGE_SIZE
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
-+typedef int gfp_t;
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
-+# define IRQF_SHARED SA_SHIRQ
-+#endif
-+
-+typedef struct os_dependent {
-+ /** Base address returned from ioremap() */
-+ void *base;
-+
-+ /** Register offset for Diagnostic API */
-+ uint32_t reg_offset;
-+
-+ /** Base address for MPHI peripheral */
-+ void *mphi_base;
-+
-+#ifdef LM_INTERFACE
-+ struct lm_device *lmdev;
-+#elif defined(PCI_INTERFACE)
-+ struct pci_dev *pcidev;
-+
-+ /** Start address of a PCI region */
-+ resource_size_t rsrc_start;
-+
-+ /** Length address of a PCI region */
-+ resource_size_t rsrc_len;
-+#elif defined(PLATFORM_INTERFACE)
-+ struct platform_device *platformdev;
-+#endif
-+
-+} os_dependent_t;
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+
-+
-+/* Type for the our device on the chosen bus */
-+#if defined(LM_INTERFACE)
-+typedef struct lm_device dwc_bus_dev_t;
-+#elif defined(PCI_INTERFACE)
-+typedef struct pci_dev dwc_bus_dev_t;
-+#elif defined(PLATFORM_INTERFACE)
-+typedef struct platform_device dwc_bus_dev_t;
-+#endif
-+
-+/* Helper macro to retrieve drvdata from the device on the chosen bus */
-+#if defined(LM_INTERFACE)
-+#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev)
-+#elif defined(PCI_INTERFACE)
-+#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev)
-+#elif defined(PLATFORM_INTERFACE)
-+#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev)
-+#endif
-+
-+/**
-+ * Helper macro returning the otg_device structure of a given struct device
-+ *
-+ * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
-+ */
-+#ifdef LM_INTERFACE
-+#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
-+ struct lm_device *lm_dev = \
-+ container_of(_dev, struct lm_device, dev); \
-+ _var = lm_get_drvdata(lm_dev); \
-+ } while (0)
-+
-+#elif defined(PCI_INTERFACE)
-+#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
-+ _var = dev_get_drvdata(_dev); \
-+ } while (0)
-+
-+#elif defined(PLATFORM_INTERFACE)
-+#define DWC_OTG_GETDRVDEV(_var, _dev) do { \
-+ struct platform_device *platform_dev = \
-+ container_of(_dev, struct platform_device, dev); \
-+ _var = platform_get_drvdata(platform_dev); \
-+ } while (0)
-+#endif
-+
-+
-+/**
-+ * Helper macro returning the struct dev of the given struct os_dependent
-+ *
-+ * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep)
-+ */
-+#ifdef LM_INTERFACE
-+#define DWC_OTG_OS_GETDEV(_osdep) \
-+ ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev)
-+#elif defined(PCI_INTERFACE)
-+#define DWC_OTG_OS_GETDEV(_osdep) \
-+ ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev)
-+#elif defined(PLATFORM_INTERFACE)
-+#define DWC_OTG_OS_GETDEV(_osdep) \
-+ ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev)
-+#endif
-+
-+
-+
-+
-+#endif /* _DWC_OS_DEP_H_ */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,2708 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
-+ * $Revision: #101 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_HOST_ONLY
-+
-+/** @file
-+ * This file implements PCD Core. All code in this file is portable and doesn't
-+ * use any OS specific functions.
-+ * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code>
-+ * header file, which can be used to implement OS specific PCD interface.
-+ *
-+ * An important function of the PCD is managing interrupts generated
-+ * by the DWC_otg controller. The implementation of the DWC_otg device
-+ * mode interrupt service routines is in dwc_otg_pcd_intr.c.
-+ *
-+ * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
-+ * @todo Does it work when the request size is greater than DEPTSIZ
-+ * transfer size
-+ *
-+ */
-+
-+#include "dwc_otg_pcd.h"
-+
-+#ifdef DWC_UTE_CFI
-+#include "dwc_otg_cfi.h"
-+
-+extern int init_cfi(cfiobject_t * cfiobj);
-+#endif
-+
-+/**
-+ * Choose endpoint from ep arrays using usb_ep structure.
-+ */
-+static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
-+{
-+ int i;
-+ if (pcd->ep0.priv == handle) {
-+ return &pcd->ep0;
-+ }
-+ for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
-+ if (pcd->in_ep[i].priv == handle)
-+ return &pcd->in_ep[i];
-+ if (pcd->out_ep[i].priv == handle)
-+ return &pcd->out_ep[i];
-+ }
-+
-+ return NULL;
-+}
-+
-+/**
-+ * This function completes a request. It call's the request call back.
-+ */
-+void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
-+ int32_t status)
-+{
-+ unsigned stopped = ep->stopped;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req);
-+ DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
-+
-+ /* don't modify queue heads during completion callback */
-+ ep->stopped = 1;
-+ /* spin_unlock/spin_lock now done in fops->complete() */
-+ ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
-+ req->actual);
-+
-+ if (ep->pcd->request_pending > 0) {
-+ --ep->pcd->request_pending;
-+ }
-+
-+ ep->stopped = stopped;
-+ DWC_FREE(req);
-+}
-+
-+/**
-+ * This function terminates all the requsts in the EP request queue.
-+ */
-+void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_otg_pcd_request_t *req;
-+
-+ ep->stopped = 1;
-+
-+ /* called with irqs blocked?? */
-+ while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
-+ }
-+}
-+
-+void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
-+ const struct dwc_otg_pcd_function_ops *fops)
-+{
-+ pcd->fops = fops;
-+}
-+
-+/**
-+ * PCD Callback function for initializing the PCD when switching to
-+ * device mode.
-+ *
-+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
-+ */
-+static int32_t dwc_otg_pcd_start_cb(void *p)
-+{
-+ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+
-+ /*
-+ * Initialized the Core for Device mode.
-+ */
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ dwc_otg_core_dev_init(core_if);
-+ /* Set core_if's lock pointer to the pcd->lock */
-+ core_if->lock = pcd->lock;
-+ }
-+ return 1;
-+}
-+
-+/** CFI-specific buffer allocation function for EP */
-+#ifdef DWC_UTE_CFI
-+uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
-+ size_t buflen, int flags)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ ep = get_ep_from_handle(pcd, pep);
-+ if (!ep) {
-+ DWC_WARN("bad ep\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
-+ flags);
-+}
-+#else
-+uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
-+ size_t buflen, int flags);
-+#endif
-+
-+/**
-+ * PCD Callback function for notifying the PCD when resuming from
-+ * suspend.
-+ *
-+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
-+ */
-+static int32_t dwc_otg_pcd_resume_cb(void *p)
-+{
-+ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
-+
-+ if (pcd->fops->resume) {
-+ pcd->fops->resume(pcd);
-+ }
-+
-+ /* Stop the SRP timeout timer. */
-+ if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
-+ || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
-+ if (GET_CORE_IF(pcd)->srp_timer_started) {
-+ GET_CORE_IF(pcd)->srp_timer_started = 0;
-+ DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer);
-+ }
-+ }
-+ return 1;
-+}
-+
-+/**
-+ * PCD Callback function for notifying the PCD device is suspended.
-+ *
-+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
-+ */
-+static int32_t dwc_otg_pcd_suspend_cb(void *p)
-+{
-+ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
-+
-+ if (pcd->fops->suspend) {
-+ DWC_SPINUNLOCK(pcd->lock);
-+ pcd->fops->suspend(pcd);
-+ DWC_SPINLOCK(pcd->lock);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * PCD Callback function for stopping the PCD when switching to Host
-+ * mode.
-+ *
-+ * @param p void pointer to the <code>dwc_otg_pcd_t</code>
-+ */
-+static int32_t dwc_otg_pcd_stop_cb(void *p)
-+{
-+ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
-+ extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
-+
-+ dwc_otg_pcd_stop(pcd);
-+ return 1;
-+}
-+
-+/**
-+ * PCD Callback structure for handling mode switching.
-+ */
-+static dwc_otg_cil_callbacks_t pcd_callbacks = {
-+ .start = dwc_otg_pcd_start_cb,
-+ .stop = dwc_otg_pcd_stop_cb,
-+ .suspend = dwc_otg_pcd_suspend_cb,
-+ .resume_wakeup = dwc_otg_pcd_resume_cb,
-+ .p = 0, /* Set at registration */
-+};
-+
-+/**
-+ * This function allocates a DMA Descriptor chain for the Endpoint
-+ * buffer to be used for a transfer to/from the specified endpoint.
-+ */
-+dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr,
-+ uint32_t count)
-+{
-+ return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t),
-+ dma_desc_addr);
-+}
-+
-+/**
-+ * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
-+ */
-+void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
-+ uint32_t dma_desc_addr, uint32_t count)
-+{
-+ DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
-+ dma_desc_addr);
-+}
-+
-+#ifdef DWC_EN_ISOC
-+
-+/**
-+ * This function initializes a descriptor chain for Isochronous transfer
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param dwc_ep The EP to start the transfer on.
-+ *
-+ */
-+void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * dwc_ep)
-+{
-+
-+ dsts_data_t dsts = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ volatile uint32_t *addr;
-+ int i, j;
-+ uint32_t len;
-+
-+ if (dwc_ep->is_in)
-+ dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
-+ else
-+ dwc_ep->desc_cnt =
-+ dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
-+ dwc_ep->bInterval;
-+
-+ /** Allocate descriptors for double buffering */
-+ dwc_ep->iso_desc_addr =
-+ dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
-+ dwc_ep->desc_cnt * 2);
-+ if (dwc_ep->desc_addr) {
-+ DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
-+ return;
-+ }
-+
-+ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+
-+ /** ISO OUT EP */
-+ if (dwc_ep->is_in == 0) {
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
-+ dma_addr_t dma_ad;
-+ uint32_t data_per_desc;
-+ dwc_otg_dev_out_ep_regs_t *out_regs =
-+ core_if->dev_if->out_ep_regs[dwc_ep->num];
-+ int offset;
-+
-+ addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
-+ dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma));
-+
-+ /** Buffer 0 descriptors setup */
-+ dma_ad = dwc_ep->dma_addr0;
-+
-+ sts.b_iso_out.bs = BS_HOST_READY;
-+ sts.b_iso_out.rxsts = 0;
-+ sts.b_iso_out.l = 0;
-+ sts.b_iso_out.sp = 0;
-+ sts.b_iso_out.ioc = 0;
-+ sts.b_iso_out.pid = 0;
-+ sts.b_iso_out.framenum = 0;
-+
-+ offset = 0;
-+ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
-+ i += dwc_ep->pkt_per_frm) {
-+
-+ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
-+ uint32_t len = (j + 1) * dwc_ep->maxpacket;
-+ if (len > dwc_ep->data_per_frame)
-+ data_per_desc =
-+ dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket;
-+ else
-+ data_per_desc = dwc_ep->maxpacket;
-+ len = data_per_desc % 4;
-+ if (len)
-+ data_per_desc += 4 - len;
-+
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ offset += data_per_desc;
-+ dma_desc++;
-+ dma_ad += data_per_desc;
-+ }
-+ }
-+
-+ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
-+ uint32_t len = (j + 1) * dwc_ep->maxpacket;
-+ if (len > dwc_ep->data_per_frame)
-+ data_per_desc =
-+ dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket;
-+ else
-+ data_per_desc = dwc_ep->maxpacket;
-+ len = data_per_desc % 4;
-+ if (len)
-+ data_per_desc += 4 - len;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ offset += data_per_desc;
-+ dma_desc++;
-+ dma_ad += data_per_desc;
-+ }
-+
-+ sts.b_iso_out.ioc = 1;
-+ len = (j + 1) * dwc_ep->maxpacket;
-+ if (len > dwc_ep->data_per_frame)
-+ data_per_desc =
-+ dwc_ep->data_per_frame - j * dwc_ep->maxpacket;
-+ else
-+ data_per_desc = dwc_ep->maxpacket;
-+ len = data_per_desc % 4;
-+ if (len)
-+ data_per_desc += 4 - len;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+ dma_desc++;
-+
-+ /** Buffer 1 descriptors setup */
-+ sts.b_iso_out.ioc = 0;
-+ dma_ad = dwc_ep->dma_addr1;
-+
-+ offset = 0;
-+ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
-+ i += dwc_ep->pkt_per_frm) {
-+ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
-+ uint32_t len = (j + 1) * dwc_ep->maxpacket;
-+ if (len > dwc_ep->data_per_frame)
-+ data_per_desc =
-+ dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket;
-+ else
-+ data_per_desc = dwc_ep->maxpacket;
-+ len = data_per_desc % 4;
-+ if (len)
-+ data_per_desc += 4 - len;
-+
-+ data_per_desc =
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ offset += data_per_desc;
-+ dma_desc++;
-+ dma_ad += data_per_desc;
-+ }
-+ }
-+ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ offset += data_per_desc;
-+ dma_desc++;
-+ dma_ad += data_per_desc;
-+ }
-+
-+ sts.b_iso_out.ioc = 1;
-+ sts.b_iso_out.l = 1;
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ dwc_ep->next_frame = 0;
-+
-+ /** Write dma_ad into DOEPDMA register */
-+ DWC_WRITE_REG32(&(out_regs->doepdma),
-+ (uint32_t) dwc_ep->iso_dma_desc_addr);
-+
-+ }
-+ /** ISO IN EP */
-+ else {
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
-+ dma_addr_t dma_ad;
-+ dwc_otg_dev_in_ep_regs_t *in_regs =
-+ core_if->dev_if->in_ep_regs[dwc_ep->num];
-+ unsigned int frmnumber;
-+ fifosize_data_t txfifosize, rxfifosize;
-+
-+ txfifosize.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
-+ dtxfsts);
-+ rxfifosize.d32 =
-+ DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
-+
-+ addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
-+
-+ dma_ad = dwc_ep->dma_addr0;
-+
-+ dsts.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+
-+ sts.b_iso_in.bs = BS_HOST_READY;
-+ sts.b_iso_in.txsts = 0;
-+ sts.b_iso_in.sp =
-+ (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
-+ sts.b_iso_in.ioc = 0;
-+ sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
-+
-+ frmnumber = dwc_ep->next_frame;
-+
-+ sts.b_iso_in.framenum = frmnumber;
-+ sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
-+ sts.b_iso_in.l = 0;
-+
-+ /** Buffer 0 descriptors setup */
-+ for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+ dma_desc++;
-+
-+ dma_ad += dwc_ep->data_per_frame;
-+ sts.b_iso_in.framenum += dwc_ep->bInterval;
-+ }
-+
-+ sts.b_iso_in.ioc = 1;
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+ ++dma_desc;
-+
-+ /** Buffer 1 descriptors setup */
-+ sts.b_iso_in.ioc = 0;
-+ dma_ad = dwc_ep->dma_addr1;
-+
-+ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
-+ i += dwc_ep->pkt_per_frm) {
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+ dma_desc++;
-+
-+ dma_ad += dwc_ep->data_per_frame;
-+ sts.b_iso_in.framenum += dwc_ep->bInterval;
-+
-+ sts.b_iso_in.ioc = 0;
-+ }
-+ sts.b_iso_in.ioc = 1;
-+ sts.b_iso_in.l = 1;
-+
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
-+
-+ /** Write dma_ad into diepdma register */
-+ DWC_WRITE_REG32(&(in_regs->diepdma),
-+ (uint32_t) dwc_ep->iso_dma_desc_addr);
-+ }
-+ /** Enable endpoint, clear nak */
-+ depctl.d32 = 0;
-+ depctl.b.epena = 1;
-+ depctl.b.usbactep = 1;
-+ depctl.b.cnak = 1;
-+
-+ DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
-+ depctl.d32 = DWC_READ_REG32(addr);
-+}
-+
-+/**
-+ * This function initializes a descriptor chain for Isochronous transfer
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ *
-+ */
-+void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl = {.d32 = 0 };
-+ volatile uint32_t *addr;
-+
-+ if (ep->is_in) {
-+ addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
-+ } else {
-+ addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
-+ }
-+
-+ if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
-+ return;
-+ } else {
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+
-+ ep->xfer_len =
-+ ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
-+ ep->pkt_cnt =
-+ (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
-+ ep->xfer_count = 0;
-+ ep->xfer_buff =
-+ (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
-+ ep->dma_addr =
-+ (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
-+
-+ if (ep->is_in) {
-+ /* Program the transfer size and packet count
-+ * as follows: xfersize = N * maxpacket +
-+ * short_packet pktcnt = N + (short_packet
-+ * exist ? 1 : 0)
-+ */
-+ deptsiz.b.mc = ep->pkt_per_frm;
-+ deptsiz.b.xfersize = ep->xfer_len;
-+ deptsiz.b.pktcnt =
-+ (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ dieptsiz, deptsiz.d32);
-+
-+ /* Write the DMA register */
-+ DWC_WRITE_REG32(&
-+ (core_if->dev_if->in_ep_regs[ep->num]->
-+ diepdma), (uint32_t) ep->dma_addr);
-+
-+ } else {
-+ deptsiz.b.pktcnt =
-+ (ep->xfer_len + (ep->maxpacket - 1)) /
-+ ep->maxpacket;
-+ deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
-+
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
-+ doeptsiz, deptsiz.d32);
-+
-+ /* Write the DMA register */
-+ DWC_WRITE_REG32(&
-+ (core_if->dev_if->out_ep_regs[ep->num]->
-+ doepdma), (uint32_t) ep->dma_addr);
-+
-+ }
-+ /** Enable endpoint, clear nak */
-+ depctl.d32 = 0;
-+ depctl.b.epena = 1;
-+ depctl.b.cnak = 1;
-+
-+ DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
-+ }
-+}
-+
-+/**
-+ * This function does the setup for a data transfer for an EP and
-+ * starts the transfer. For an IN transfer, the packets will be
-+ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
-+ * the packets are unloaded from the Rx FIFO in the ISR.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ */
-+
-+static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * ep)
-+{
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable) {
-+ if (ep->is_in) {
-+ ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
-+ } else {
-+ ep->desc_cnt = ep->pkt_cnt;
-+ }
-+ dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
-+ } else {
-+ if (core_if->pti_enh_enable) {
-+ dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
-+ } else {
-+ ep->cur_pkt_addr =
-+ (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
-+ xfer_buff0;
-+ ep->cur_pkt_dma_addr =
-+ (ep->proc_buf_num) ? ep->dma_addr1 : ep->
-+ dma_addr0;
-+ dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
-+ }
-+ }
-+ } else {
-+ ep->cur_pkt_addr =
-+ (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
-+ ep->cur_pkt_dma_addr =
-+ (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
-+ dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
-+ }
-+}
-+
-+/**
-+ * This function stops transfer for an EP and
-+ * resets the ep's variables.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ */
-+
-+void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ depctl_data_t depctl = {.d32 = 0 };
-+ volatile uint32_t *addr;
-+
-+ if (ep->is_in == 1) {
-+ addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
-+ } else {
-+ addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
-+ }
-+
-+ /* disable the ep */
-+ depctl.d32 = DWC_READ_REG32(addr);
-+
-+ depctl.b.epdis = 1;
-+ depctl.b.snak = 1;
-+
-+ DWC_WRITE_REG32(addr, depctl.d32);
-+
-+ if (core_if->dma_desc_enable &&
-+ ep->iso_desc_addr && ep->iso_dma_desc_addr) {
-+ dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
-+ ep->iso_dma_desc_addr,
-+ ep->desc_cnt * 2);
-+ }
-+
-+ /* reset varibales */
-+ ep->dma_addr0 = 0;
-+ ep->dma_addr1 = 0;
-+ ep->xfer_buff0 = 0;
-+ ep->xfer_buff1 = 0;
-+ ep->data_per_frame = 0;
-+ ep->data_pattern_frame = 0;
-+ ep->sync_frame = 0;
-+ ep->buf_proc_intrvl = 0;
-+ ep->bInterval = 0;
-+ ep->proc_buf_num = 0;
-+ ep->pkt_per_frm = 0;
-+ ep->pkt_per_frm = 0;
-+ ep->desc_cnt = 0;
-+ ep->iso_desc_addr = 0;
-+ ep->iso_dma_desc_addr = 0;
-+}
-+
-+int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
-+ dwc_dma_t dma1, int sync_frame, int dp_frame,
-+ int data_per_frame, int start_frame,
-+ int buf_proc_intrvl, void *req_handle,
-+ int atomic_alloc)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_irqflags_t flags = 0;
-+ dwc_ep_t *dwc_ep;
-+ int32_t frm_data;
-+ dsts_data_t dsts;
-+ dwc_otg_core_if_t *core_if;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+
-+ if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
-+ DWC_WARN("bad ep\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+ core_if = GET_CORE_IF(pcd);
-+ dwc_ep = &ep->dwc_ep;
-+
-+ if (ep->iso_req_handle) {
-+ DWC_WARN("ISO request in progress\n");
-+ }
-+
-+ dwc_ep->dma_addr0 = dma0;
-+ dwc_ep->dma_addr1 = dma1;
-+
-+ dwc_ep->xfer_buff0 = buf0;
-+ dwc_ep->xfer_buff1 = buf1;
-+
-+ dwc_ep->data_per_frame = data_per_frame;
-+
-+ /** @todo - pattern data support is to be implemented in the future */
-+ dwc_ep->data_pattern_frame = dp_frame;
-+ dwc_ep->sync_frame = sync_frame;
-+
-+ dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
-+
-+ dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
-+
-+ dwc_ep->proc_buf_num = 0;
-+
-+ dwc_ep->pkt_per_frm = 0;
-+ frm_data = ep->dwc_ep.data_per_frame;
-+ while (frm_data > 0) {
-+ dwc_ep->pkt_per_frm++;
-+ frm_data -= ep->dwc_ep.maxpacket;
-+ }
-+
-+ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+
-+ if (start_frame == -1) {
-+ dwc_ep->next_frame = dsts.b.soffn + 1;
-+ if (dwc_ep->bInterval != 1) {
-+ dwc_ep->next_frame =
-+ dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
-+ dwc_ep->next_frame %
-+ dwc_ep->bInterval);
-+ }
-+ } else {
-+ dwc_ep->next_frame = start_frame;
-+ }
-+
-+ if (!core_if->pti_enh_enable) {
-+ dwc_ep->pkt_cnt =
-+ dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
-+ dwc_ep->bInterval;
-+ } else {
-+ dwc_ep->pkt_cnt =
-+ (dwc_ep->data_per_frame *
-+ (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
-+ - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
-+ }
-+
-+ if (core_if->dma_desc_enable) {
-+ dwc_ep->desc_cnt =
-+ dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
-+ dwc_ep->bInterval;
-+ }
-+
-+ if (atomic_alloc) {
-+ dwc_ep->pkt_info =
-+ DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
-+ } else {
-+ dwc_ep->pkt_info =
-+ DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
-+ }
-+ if (!dwc_ep->pkt_info) {
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ if (core_if->pti_enh_enable) {
-+ dwc_memset(dwc_ep->pkt_info, 0,
-+ sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
-+ }
-+
-+ dwc_ep->cur_pkt = 0;
-+ ep->iso_req_handle = req_handle;
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
-+ return 0;
-+}
-+
-+int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle)
-+{
-+ dwc_irqflags_t flags = 0;
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+ if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
-+ DWC_WARN("bad ep\n");
-+ return -DWC_E_INVALID;
-+ }
-+ dwc_ep = &ep->dwc_ep;
-+
-+ dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
-+
-+ DWC_FREE(dwc_ep->pkt_info);
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+ if (ep->iso_req_handle != req_handle) {
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+ ep->iso_req_handle = 0;
-+ return 0;
-+}
-+
-+/**
-+ * This function is used for perodical data exchnage between PCD and gadget drivers.
-+ * for Isochronous EPs
-+ *
-+ * - Every time a sync period completes this function is called to
-+ * perform data exchange between PCD and gadget
-+ */
-+void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
-+ void *req_handle)
-+{
-+ int i;
-+ dwc_ep_t *dwc_ep;
-+
-+ dwc_ep = &ep->dwc_ep;
-+
-+ DWC_SPINUNLOCK(ep->pcd->lock);
-+ pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
-+ dwc_ep->proc_buf_num ^ 0x1);
-+ DWC_SPINLOCK(ep->pcd->lock);
-+
-+ for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
-+ dwc_ep->pkt_info[i].status = 0;
-+ dwc_ep->pkt_info[i].offset = 0;
-+ dwc_ep->pkt_info[i].length = 0;
-+ }
-+}
-+
-+int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *iso_req_handle)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+ if (!ep->desc || ep->dwc_ep.num == 0) {
-+ DWC_WARN("bad ep\n");
-+ return -DWC_E_INVALID;
-+ }
-+ dwc_ep = &ep->dwc_ep;
-+
-+ return dwc_ep->pkt_cnt;
-+}
-+
-+void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *iso_req_handle, int packet,
-+ int *status, int *actual, int *offset)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+ if (!ep)
-+ DWC_WARN("bad ep\n");
-+
-+ dwc_ep = &ep->dwc_ep;
-+
-+ *status = dwc_ep->pkt_info[packet].status;
-+ *actual = dwc_ep->pkt_info[packet].length;
-+ *offset = dwc_ep->pkt_info[packet].offset;
-+}
-+
-+#endif /* DWC_EN_ISOC */
-+
-+static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
-+ uint32_t is_in, uint32_t ep_num)
-+{
-+ /* Init EP structure */
-+ pcd_ep->desc = 0;
-+ pcd_ep->pcd = pcd;
-+ pcd_ep->stopped = 1;
-+ pcd_ep->queue_sof = 0;
-+
-+ /* Init DWC ep structure */
-+ pcd_ep->dwc_ep.is_in = is_in;
-+ pcd_ep->dwc_ep.num = ep_num;
-+ pcd_ep->dwc_ep.active = 0;
-+ pcd_ep->dwc_ep.tx_fifo_num = 0;
-+ /* Control until ep is actvated */
-+ pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
-+ pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
-+ pcd_ep->dwc_ep.dma_addr = 0;
-+ pcd_ep->dwc_ep.start_xfer_buff = 0;
-+ pcd_ep->dwc_ep.xfer_buff = 0;
-+ pcd_ep->dwc_ep.xfer_len = 0;
-+ pcd_ep->dwc_ep.xfer_count = 0;
-+ pcd_ep->dwc_ep.sent_zlp = 0;
-+ pcd_ep->dwc_ep.total_len = 0;
-+ pcd_ep->dwc_ep.desc_addr = 0;
-+ pcd_ep->dwc_ep.dma_desc_addr = 0;
-+ DWC_CIRCLEQ_INIT(&pcd_ep->queue);
-+}
-+
-+/**
-+ * Initialize ep's
-+ */
-+static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
-+{
-+ int i;
-+ uint32_t hwcfg1;
-+ dwc_otg_pcd_ep_t *ep;
-+ int in_ep_cntr, out_ep_cntr;
-+ uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
-+ uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
-+
-+ /**
-+ * Initialize the EP0 structure.
-+ */
-+ ep = &pcd->ep0;
-+ dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
-+
-+ in_ep_cntr = 0;
-+ hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
-+ for (i = 1; in_ep_cntr < num_in_eps; i++) {
-+ if ((hwcfg1 & 0x1) == 0) {
-+ dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
-+ in_ep_cntr++;
-+ /**
-+ * @todo NGS: Add direction to EP, based on contents
-+ * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
-+ * sprintf(";r
-+ */
-+ dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
-+
-+ DWC_CIRCLEQ_INIT(&ep->queue);
-+ }
-+ hwcfg1 >>= 2;
-+ }
-+
-+ out_ep_cntr = 0;
-+ hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
-+ for (i = 1; out_ep_cntr < num_out_eps; i++) {
-+ if ((hwcfg1 & 0x1) == 0) {
-+ dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
-+ out_ep_cntr++;
-+ /**
-+ * @todo NGS: Add direction to EP, based on contents
-+ * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
-+ * sprintf(";r
-+ */
-+ dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
-+ DWC_CIRCLEQ_INIT(&ep->queue);
-+ }
-+ hwcfg1 >>= 2;
-+ }
-+
-+ pcd->ep0state = EP0_DISCONNECT;
-+ pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
-+ pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
-+}
-+
-+/**
-+ * This function is called when the SRP timer expires. The SRP should
-+ * complete within 6 seconds.
-+ */
-+static void srp_timeout(void *ptr)
-+{
-+ gotgctl_data_t gotgctl;
-+ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
-+ volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
-+
-+ gotgctl.d32 = DWC_READ_REG32(addr);
-+
-+ core_if->srp_timer_started = 0;
-+
-+ if (core_if->adp_enable) {
-+ if (gotgctl.b.bsesvld == 0) {
-+ gpwrdn_data_t gpwrdn = {.d32 = 0 };
-+ DWC_PRINTF("SRP Timeout BSESSVLD = 0\n");
-+ /* Power off the core */
-+ if (core_if->power_down == 2) {
-+ gpwrdn.b.pwrdnswtch = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->gpwrdn,
-+ gpwrdn.d32, 0);
-+ }
-+
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuintsel = 1;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
-+ gpwrdn.d32);
-+ dwc_otg_adp_probe_start(core_if);
-+ } else {
-+ DWC_PRINTF("SRP Timeout BSESSVLD = 1\n");
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+ }
-+ }
-+
-+ if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
-+ (core_if->core_params->i2c_enable)) {
-+ DWC_PRINTF("SRP Timeout\n");
-+
-+ if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
-+ if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
-+ core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
-+ }
-+
-+ /* Clear Session Request */
-+ gotgctl.d32 = 0;
-+ gotgctl.b.sesreq = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
-+ gotgctl.d32, 0);
-+
-+ core_if->srp_success = 0;
-+ } else {
-+ __DWC_ERROR("Device not connected/responding\n");
-+ gotgctl.b.sesreq = 0;
-+ DWC_WRITE_REG32(addr, gotgctl.d32);
-+ }
-+ } else if (gotgctl.b.sesreq) {
-+ DWC_PRINTF("SRP Timeout\n");
-+
-+ __DWC_ERROR("Device not connected/responding\n");
-+ gotgctl.b.sesreq = 0;
-+ DWC_WRITE_REG32(addr, gotgctl.d32);
-+ } else {
-+ DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
-+ }
-+}
-+
-+/**
-+ * Tasklet
-+ *
-+ */
-+extern void start_next_request(dwc_otg_pcd_ep_t * ep);
-+
-+static void start_xfer_tasklet_func(void *data)
-+{
-+ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+
-+ int i;
-+ depctl_data_t diepctl;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
-+
-+ diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl);
-+
-+ if (pcd->ep0.queue_sof) {
-+ pcd->ep0.queue_sof = 0;
-+ start_next_request(&pcd->ep0);
-+ // break;
-+ }
-+
-+ for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
-+ depctl_data_t diepctl;
-+ diepctl.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
-+
-+ if (pcd->in_ep[i].queue_sof) {
-+ pcd->in_ep[i].queue_sof = 0;
-+ start_next_request(&pcd->in_ep[i]);
-+ // break;
-+ }
-+ }
-+
-+ return;
-+}
-+
-+/**
-+ * This function initialized the PCD portion of the driver.
-+ *
-+ */
-+dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_pcd_t *pcd = NULL;
-+ dwc_otg_dev_if_t *dev_if;
-+ int i;
-+
-+ /*
-+ * Allocate PCD structure
-+ */
-+ pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t));
-+
-+ if (pcd == NULL) {
-+ return NULL;
-+ }
-+
-+ pcd->lock = DWC_SPINLOCK_ALLOC();
-+ DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n",
-+ pcd, core_if);//GRAYG
-+ if (!pcd->lock) {
-+ DWC_ERROR("Could not allocate lock for pcd");
-+ DWC_FREE(pcd);
-+ return NULL;
-+ }
-+ /* Set core_if's lock pointer to hcd->lock */
-+ core_if->lock = pcd->lock;
-+ pcd->core_if = core_if;
-+
-+ dev_if = core_if->dev_if;
-+ dev_if->isoc_ep = NULL;
-+
-+ if (core_if->hwcfg4.b.ded_fifo_en) {
-+ DWC_PRINTF("Dedicated Tx FIFOs mode\n");
-+ } else {
-+ DWC_PRINTF("Shared Tx FIFO mode\n");
-+ }
-+
-+ /*
-+ * Initialized the Core for Device mode here if there is nod ADP support.
-+ * Otherwise it will be done later in dwc_otg_adp_start routine.
-+ */
-+ if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) {
-+ dwc_otg_core_dev_init(core_if);
-+ }
-+
-+ /*
-+ * Register the PCD Callbacks.
-+ */
-+ dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
-+
-+ /*
-+ * Initialize the DMA buffer for SETUP packets
-+ */
-+ if (GET_CORE_IF(pcd)->dma_enable) {
-+ pcd->setup_pkt =
-+ DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5,
-+ &pcd->setup_pkt_dma_handle);
-+ if (pcd->setup_pkt == NULL) {
-+ DWC_FREE(pcd);
-+ return NULL;
-+ }
-+
-+ pcd->status_buf =
-+ DWC_DMA_ALLOC(sizeof(uint16_t),
-+ &pcd->status_buf_dma_handle);
-+ if (pcd->status_buf == NULL) {
-+ DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
-+ pcd->setup_pkt, pcd->setup_pkt_dma_handle);
-+ DWC_FREE(pcd);
-+ return NULL;
-+ }
-+
-+ if (GET_CORE_IF(pcd)->dma_desc_enable) {
-+ dev_if->setup_desc_addr[0] =
-+ dwc_otg_ep_alloc_desc_chain
-+ (&dev_if->dma_setup_desc_addr[0], 1);
-+ dev_if->setup_desc_addr[1] =
-+ dwc_otg_ep_alloc_desc_chain
-+ (&dev_if->dma_setup_desc_addr[1], 1);
-+ dev_if->in_desc_addr =
-+ dwc_otg_ep_alloc_desc_chain
-+ (&dev_if->dma_in_desc_addr, 1);
-+ dev_if->out_desc_addr =
-+ dwc_otg_ep_alloc_desc_chain
-+ (&dev_if->dma_out_desc_addr, 1);
-+ pcd->data_terminated = 0;
-+
-+ if (dev_if->setup_desc_addr[0] == 0
-+ || dev_if->setup_desc_addr[1] == 0
-+ || dev_if->in_desc_addr == 0
-+ || dev_if->out_desc_addr == 0) {
-+
-+ if (dev_if->out_desc_addr)
-+ dwc_otg_ep_free_desc_chain
-+ (dev_if->out_desc_addr,
-+ dev_if->dma_out_desc_addr, 1);
-+ if (dev_if->in_desc_addr)
-+ dwc_otg_ep_free_desc_chain
-+ (dev_if->in_desc_addr,
-+ dev_if->dma_in_desc_addr, 1);
-+ if (dev_if->setup_desc_addr[1])
-+ dwc_otg_ep_free_desc_chain
-+ (dev_if->setup_desc_addr[1],
-+ dev_if->dma_setup_desc_addr[1], 1);
-+ if (dev_if->setup_desc_addr[0])
-+ dwc_otg_ep_free_desc_chain
-+ (dev_if->setup_desc_addr[0],
-+ dev_if->dma_setup_desc_addr[0], 1);
-+
-+ DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5,
-+ pcd->setup_pkt,
-+ pcd->setup_pkt_dma_handle);
-+ DWC_DMA_FREE(sizeof(*pcd->status_buf),
-+ pcd->status_buf,
-+ pcd->status_buf_dma_handle);
-+
-+ DWC_FREE(pcd);
-+
-+ return NULL;
-+ }
-+ }
-+ } else {
-+ pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5);
-+ if (pcd->setup_pkt == NULL) {
-+ DWC_FREE(pcd);
-+ return NULL;
-+ }
-+
-+ pcd->status_buf = DWC_ALLOC(sizeof(uint16_t));
-+ if (pcd->status_buf == NULL) {
-+ DWC_FREE(pcd->setup_pkt);
-+ DWC_FREE(pcd);
-+ return NULL;
-+ }
-+ }
-+
-+ dwc_otg_pcd_reinit(pcd);
-+
-+ /* Allocate the cfi object for the PCD */
-+#ifdef DWC_UTE_CFI
-+ pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t));
-+ if (NULL == pcd->cfi)
-+ goto fail;
-+ if (init_cfi(pcd->cfi)) {
-+ CFI_INFO("%s: Failed to init the CFI object\n", __func__);
-+ goto fail;
-+ }
-+#endif
-+
-+ /* Initialize tasklets */
-+ pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet",
-+ start_xfer_tasklet_func, pcd);
-+ pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet",
-+ do_test_mode, pcd);
-+
-+ /* Initialize SRP timer */
-+ core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
-+
-+ if (core_if->core_params->dev_out_nak) {
-+ /**
-+ * Initialize xfer timeout timer. Implemented for
-+ * 2.93a feature "Device DDMA OUT NAK Enhancement"
-+ */
-+ for(i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ pcd->core_if->ep_xfer_timer[i] =
-+ DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout,
-+ &pcd->core_if->ep_xfer_info[i]);
-+ }
-+ }
-+
-+ return pcd;
-+#ifdef DWC_UTE_CFI
-+fail:
-+#endif
-+ if (pcd->setup_pkt)
-+ DWC_FREE(pcd->setup_pkt);
-+ if (pcd->status_buf)
-+ DWC_FREE(pcd->status_buf);
-+#ifdef DWC_UTE_CFI
-+ if (pcd->cfi)
-+ DWC_FREE(pcd->cfi);
-+#endif
-+ if (pcd)
-+ DWC_FREE(pcd);
-+ return NULL;
-+
-+}
-+
-+/**
-+ * Remove PCD specific data
-+ */
-+void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
-+ int i;
-+ if (pcd->core_if->core_params->dev_out_nak) {
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]);
-+ pcd->core_if->ep_xfer_info[i].state = 0;
-+ }
-+ }
-+
-+ if (GET_CORE_IF(pcd)->dma_enable) {
-+ DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
-+ pcd->setup_pkt_dma_handle);
-+ DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf,
-+ pcd->status_buf_dma_handle);
-+ if (GET_CORE_IF(pcd)->dma_desc_enable) {
-+ dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
-+ dev_if->dma_setup_desc_addr
-+ [0], 1);
-+ dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
-+ dev_if->dma_setup_desc_addr
-+ [1], 1);
-+ dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
-+ dev_if->dma_in_desc_addr, 1);
-+ dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
-+ dev_if->dma_out_desc_addr,
-+ 1);
-+ }
-+ } else {
-+ DWC_FREE(pcd->setup_pkt);
-+ DWC_FREE(pcd->status_buf);
-+ }
-+ DWC_SPINLOCK_FREE(pcd->lock);
-+ /* Set core_if's lock pointer to NULL */
-+ pcd->core_if->lock = NULL;
-+
-+ DWC_TASK_FREE(pcd->start_xfer_tasklet);
-+ DWC_TASK_FREE(pcd->test_mode_tasklet);
-+ if (pcd->core_if->core_params->dev_out_nak) {
-+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-+ if (pcd->core_if->ep_xfer_timer[i]) {
-+ DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]);
-+ }
-+ }
-+ }
-+
-+/* Release the CFI object's dynamic memory */
-+#ifdef DWC_UTE_CFI
-+ if (pcd->cfi->ops.release) {
-+ pcd->cfi->ops.release(pcd->cfi);
-+ }
-+#endif
-+
-+ DWC_FREE(pcd);
-+}
-+
-+/**
-+ * Returns whether registered pcd is dual speed or not
-+ */
-+uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+
-+ if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
-+ ((core_if->hwcfg2.b.hs_phy_type == 2) &&
-+ (core_if->hwcfg2.b.fs_phy_type == 1) &&
-+ (core_if->core_params->ulpi_fs_ls))) {
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * Returns whether registered pcd is OTG capable or not
-+ */
-+uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ gusbcfg_data_t usbcfg = {.d32 = 0 };
-+
-+ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
-+ if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * This function assigns periodic Tx FIFO to an periodic EP
-+ * in shared Tx FIFO mode
-+ */
-+static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t TxMsk = 1;
-+ int i;
-+
-+ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
-+ if ((TxMsk & core_if->tx_msk) == 0) {
-+ core_if->tx_msk |= TxMsk;
-+ return i + 1;
-+ }
-+ TxMsk <<= 1;
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * This function assigns periodic Tx FIFO to an periodic EP
-+ * in shared Tx FIFO mode
-+ */
-+static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
-+{
-+ uint32_t PerTxMsk = 1;
-+ int i;
-+ for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
-+ if ((PerTxMsk & core_if->p_tx_msk) == 0) {
-+ core_if->p_tx_msk |= PerTxMsk;
-+ return i + 1;
-+ }
-+ PerTxMsk <<= 1;
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * This function releases periodic Tx FIFO
-+ * in shared Tx FIFO mode
-+ */
-+static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
-+ uint32_t fifo_num)
-+{
-+ core_if->p_tx_msk =
-+ (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
-+}
-+
-+/**
-+ * This function releases periodic Tx FIFO
-+ * in shared Tx FIFO mode
-+ */
-+static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
-+{
-+ core_if->tx_msk =
-+ (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
-+}
-+
-+/**
-+ * This function is being called from gadget
-+ * to enable PCD endpoint.
-+ */
-+int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
-+ const uint8_t * ep_desc, void *usb_ep)
-+{
-+ int num, dir;
-+ dwc_otg_pcd_ep_t *ep = NULL;
-+ const usb_endpoint_descriptor_t *desc;
-+ dwc_irqflags_t flags;
-+ fifosize_data_t dptxfsiz = {.d32 = 0 };
-+ gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
-+ gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
-+ int retval = 0;
-+ int i, epcount;
-+
-+ desc = (const usb_endpoint_descriptor_t *)ep_desc;
-+
-+ if (!desc) {
-+ pcd->ep0.priv = usb_ep;
-+ ep = &pcd->ep0;
-+ retval = -DWC_E_INVALID;
-+ goto out;
-+ }
-+
-+ num = UE_GET_ADDR(desc->bEndpointAddress);
-+ dir = UE_GET_DIR(desc->bEndpointAddress);
-+
-+ if (!desc->wMaxPacketSize) {
-+ DWC_WARN("bad maxpacketsize\n");
-+ retval = -DWC_E_INVALID;
-+ goto out;
-+ }
-+
-+ if (dir == UE_DIR_IN) {
-+ epcount = pcd->core_if->dev_if->num_in_eps;
-+ for (i = 0; i < epcount; i++) {
-+ if (num == pcd->in_ep[i].dwc_ep.num) {
-+ ep = &pcd->in_ep[i];
-+ break;
-+ }
-+ }
-+ } else {
-+ epcount = pcd->core_if->dev_if->num_out_eps;
-+ for (i = 0; i < epcount; i++) {
-+ if (num == pcd->out_ep[i].dwc_ep.num) {
-+ ep = &pcd->out_ep[i];
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (!ep) {
-+ DWC_WARN("bad address\n");
-+ retval = -DWC_E_INVALID;
-+ goto out;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+
-+ ep->desc = desc;
-+ ep->priv = usb_ep;
-+
-+ /*
-+ * Activate the EP
-+ */
-+ ep->stopped = 0;
-+
-+ ep->dwc_ep.is_in = (dir == UE_DIR_IN);
-+ ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
-+
-+ ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
-+
-+ if (ep->dwc_ep.is_in) {
-+ if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
-+ ep->dwc_ep.tx_fifo_num = 0;
-+
-+ if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
-+ /*
-+ * if ISOC EP then assign a Periodic Tx FIFO.
-+ */
-+ ep->dwc_ep.tx_fifo_num =
-+ assign_perio_tx_fifo(GET_CORE_IF(pcd));
-+ }
-+ } else {
-+ /*
-+ * if Dedicated FIFOs mode is on then assign a Tx FIFO.
-+ */
-+ ep->dwc_ep.tx_fifo_num =
-+ assign_tx_fifo(GET_CORE_IF(pcd));
-+ }
-+
-+ /* Calculating EP info controller base address */
-+ if (ep->dwc_ep.tx_fifo_num
-+ && GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
-+ gdfifocfg.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->
-+ core_global_regs->gdfifocfg);
-+ gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
-+ dptxfsiz.d32 =
-+ (DWC_READ_REG32
-+ (&GET_CORE_IF(pcd)->core_global_regs->
-+ dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16);
-+ gdfifocfg.b.epinfobase =
-+ gdfifocfgbase.d32 + dptxfsiz.d32;
-+ if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
-+ core_global_regs->gdfifocfg,
-+ gdfifocfg.d32);
-+ }
-+ }
-+ }
-+ /* Set initial data PID. */
-+ if (ep->dwc_ep.type == UE_BULK) {
-+ ep->dwc_ep.data_pid_start = 0;
-+ }
-+
-+ /* Alloc DMA Descriptors */
-+ if (GET_CORE_IF(pcd)->dma_desc_enable) {
-+#ifndef DWC_UTE_PER_IO
-+ if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
-+#endif
-+ ep->dwc_ep.desc_addr =
-+ dwc_otg_ep_alloc_desc_chain(&ep->
-+ dwc_ep.dma_desc_addr,
-+ MAX_DMA_DESC_CNT);
-+ if (!ep->dwc_ep.desc_addr) {
-+ DWC_WARN("%s, can't allocate DMA descriptor\n",
-+ __func__);
-+ retval = -DWC_E_SHUTDOWN;
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ goto out;
-+ }
-+#ifndef DWC_UTE_PER_IO
-+ }
-+#endif
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
-+ (ep->dwc_ep.is_in ? "IN" : "OUT"),
-+ ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
-+#ifdef DWC_UTE_PER_IO
-+ ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1);
-+#endif
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1);
-+ ep->dwc_ep.frame_num = 0xFFFFFFFF;
-+ }
-+
-+ dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
-+
-+#ifdef DWC_UTE_CFI
-+ if (pcd->cfi->ops.ep_enable) {
-+ pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
-+ }
-+#endif
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+out:
-+ return retval;
-+}
-+
-+/**
-+ * This function is being called from gadget
-+ * to disable PCD endpoint.
-+ */
-+int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_irqflags_t flags;
-+ dwc_otg_dev_dma_desc_t *desc_addr;
-+ dwc_dma_t dma_desc_addr;
-+ gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 };
-+ gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
-+ fifosize_data_t dptxfsiz = {.d32 = 0 };
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+
-+ if (!ep || !ep->desc) {
-+ DWC_DEBUGPL(DBG_PCD, "bad ep address\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+
-+ dwc_otg_request_nuke(ep);
-+
-+ dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
-+ if (pcd->core_if->core_params->dev_out_nak) {
-+ DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]);
-+ pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0;
-+ }
-+ ep->desc = NULL;
-+ ep->stopped = 1;
-+
-+ gdfifocfg.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg);
-+ gdfifocfgbase.d32 = gdfifocfg.d32 >> 16;
-+
-+ if (ep->dwc_ep.is_in) {
-+ if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
-+ /* Flush the Tx FIFO */
-+ dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd),
-+ ep->dwc_ep.tx_fifo_num);
-+ }
-+ release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
-+ release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
-+ if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
-+ /* Decreasing EPinfo Base Addr */
-+ dptxfsiz.d32 =
-+ (DWC_READ_REG32
-+ (&GET_CORE_IF(pcd)->
-+ core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16);
-+ gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32;
-+ if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) {
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg,
-+ gdfifocfg.d32);
-+ }
-+ }
-+ }
-+
-+ /* Free DMA Descriptors */
-+ if (GET_CORE_IF(pcd)->dma_desc_enable) {
-+ if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
-+ desc_addr = ep->dwc_ep.desc_addr;
-+ dma_desc_addr = ep->dwc_ep.dma_desc_addr;
-+
-+ /* Cannot call dma_free_coherent() with IRQs disabled */
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
-+ MAX_DMA_DESC_CNT);
-+
-+ goto out_unlocked;
-+ }
-+ }
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+out_unlocked:
-+ DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
-+ ep->dwc_ep.is_in ? "IN" : "OUT");
-+ return 0;
-+
-+}
-+
-+/******************************************************************************/
-+#ifdef DWC_UTE_PER_IO
-+
-+/**
-+ * Free the request and its extended parts
-+ *
-+ */
-+void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req)
-+{
-+ DWC_FREE(req->ext_req.per_io_frame_descs);
-+ DWC_FREE(req);
-+}
-+
-+/**
-+ * Start the next request in the endpoint's queue.
-+ *
-+ */
-+int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd,
-+ dwc_otg_pcd_ep_t * ep)
-+{
-+ int i;
-+ dwc_otg_pcd_request_t *req = NULL;
-+ dwc_ep_t *dwcep = NULL;
-+ struct dwc_iso_xreq_port *ereq = NULL;
-+ struct dwc_iso_pkt_desc_port *ddesc_iso;
-+ uint16_t nat;
-+ depctl_data_t diepctl;
-+
-+ dwcep = &ep->dwc_ep;
-+
-+ if (dwcep->xiso_active_xfers > 0) {
-+#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers
-+ DWC_WARN("There are currently active transfers for EP%d \
-+ (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers,
-+ dwcep->xiso_queued_xfers);
-+#endif
-+ return 0;
-+ }
-+
-+ nat = UGETW(ep->desc->wMaxPacketSize);
-+ nat = (nat >> 11) & 0x03;
-+
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ ereq = &req->ext_req;
-+ ep->stopped = 0;
-+
-+ /* Get the frame number */
-+ dwcep->xiso_frame_num =
-+ dwc_otg_get_frame_number(GET_CORE_IF(pcd));
-+ DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num);
-+
-+ ddesc_iso = ereq->per_io_frame_descs;
-+
-+ if (dwcep->is_in) {
-+ /* Setup DMA Descriptor chain for IN Isoc request */
-+ for (i = 0; i < ereq->pio_pkt_count; i++) {
-+ //if ((i % (nat + 1)) == 0)
-+ if ( i > 0 )
-+ dwcep->xiso_frame_num =
-+ (dwcep->xiso_bInterval +
-+ dwcep->xiso_frame_num) & 0x3FFF;
-+ dwcep->desc_addr[i].buf =
-+ req->dma + ddesc_iso[i].offset;
-+ dwcep->desc_addr[i].status.b_iso_in.txbytes =
-+ ddesc_iso[i].length;
-+ dwcep->desc_addr[i].status.b_iso_in.framenum =
-+ dwcep->xiso_frame_num;
-+ dwcep->desc_addr[i].status.b_iso_in.bs =
-+ BS_HOST_READY;
-+ dwcep->desc_addr[i].status.b_iso_in.txsts = 0;
-+ dwcep->desc_addr[i].status.b_iso_in.sp =
-+ (ddesc_iso[i].length %
-+ dwcep->maxpacket) ? 1 : 0;
-+ dwcep->desc_addr[i].status.b_iso_in.ioc = 0;
-+ dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1;
-+ dwcep->desc_addr[i].status.b_iso_in.l = 0;
-+
-+ /* Process the last descriptor */
-+ if (i == ereq->pio_pkt_count - 1) {
-+ dwcep->desc_addr[i].status.b_iso_in.ioc = 1;
-+ dwcep->desc_addr[i].status.b_iso_in.l = 1;
-+ }
-+ }
-+
-+ /* Setup and start the transfer for this endpoint */
-+ dwcep->xiso_active_xfers++;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if->
-+ in_ep_regs[dwcep->num]->diepdma,
-+ dwcep->dma_desc_addr);
-+ diepctl.d32 = 0;
-+ diepctl.b.epena = 1;
-+ diepctl.b.cnak = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if->
-+ in_ep_regs[dwcep->num]->diepctl, 0,
-+ diepctl.d32);
-+ } else {
-+ /* Setup DMA Descriptor chain for OUT Isoc request */
-+ for (i = 0; i < ereq->pio_pkt_count; i++) {
-+ //if ((i % (nat + 1)) == 0)
-+ dwcep->xiso_frame_num = (dwcep->xiso_bInterval +
-+ dwcep->xiso_frame_num) & 0x3FFF;
-+ dwcep->desc_addr[i].buf =
-+ req->dma + ddesc_iso[i].offset;
-+ dwcep->desc_addr[i].status.b_iso_out.rxbytes =
-+ ddesc_iso[i].length;
-+ dwcep->desc_addr[i].status.b_iso_out.framenum =
-+ dwcep->xiso_frame_num;
-+ dwcep->desc_addr[i].status.b_iso_out.bs =
-+ BS_HOST_READY;
-+ dwcep->desc_addr[i].status.b_iso_out.rxsts = 0;
-+ dwcep->desc_addr[i].status.b_iso_out.sp =
-+ (ddesc_iso[i].length %
-+ dwcep->maxpacket) ? 1 : 0;
-+ dwcep->desc_addr[i].status.b_iso_out.ioc = 0;
-+ dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1;
-+ dwcep->desc_addr[i].status.b_iso_out.l = 0;
-+
-+ /* Process the last descriptor */
-+ if (i == ereq->pio_pkt_count - 1) {
-+ dwcep->desc_addr[i].status.b_iso_out.ioc = 1;
-+ dwcep->desc_addr[i].status.b_iso_out.l = 1;
-+ }
-+ }
-+
-+ /* Setup and start the transfer for this endpoint */
-+ dwcep->xiso_active_xfers++;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
-+ dev_if->out_ep_regs[dwcep->num]->
-+ doepdma, dwcep->dma_desc_addr);
-+ diepctl.d32 = 0;
-+ diepctl.b.epena = 1;
-+ diepctl.b.cnak = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
-+ dev_if->out_ep_regs[dwcep->num]->
-+ doepctl, 0, diepctl.d32);
-+ }
-+
-+ } else {
-+ ep->stopped = 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * - Remove the request from the queue
-+ */
-+void complete_xiso_ep(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_otg_pcd_request_t *req = NULL;
-+ struct dwc_iso_xreq_port *ereq = NULL;
-+ struct dwc_iso_pkt_desc_port *ddesc_iso = NULL;
-+ dwc_ep_t *dwcep = NULL;
-+ int i;
-+
-+ //DWC_DEBUG();
-+ dwcep = &ep->dwc_ep;
-+
-+ /* Get the first pending request from the queue */
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ if (!req) {
-+ DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
-+ return;
-+ }
-+ dwcep->xiso_active_xfers--;
-+ dwcep->xiso_queued_xfers--;
-+ /* Remove this request from the queue */
-+ DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
-+ } else {
-+ DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
-+ return;
-+ }
-+
-+ ep->stopped = 1;
-+ ereq = &req->ext_req;
-+ ddesc_iso = ereq->per_io_frame_descs;
-+
-+ if (dwcep->xiso_active_xfers < 0) {
-+ DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num,
-+ dwcep->xiso_active_xfers);
-+ }
-+
-+ /* Fill the Isoc descs of portable extended req from dma descriptors */
-+ for (i = 0; i < ereq->pio_pkt_count; i++) {
-+ if (dwcep->is_in) { /* IN endpoints */
-+ ddesc_iso[i].actual_length = ddesc_iso[i].length -
-+ dwcep->desc_addr[i].status.b_iso_in.txbytes;
-+ ddesc_iso[i].status =
-+ dwcep->desc_addr[i].status.b_iso_in.txsts;
-+ } else { /* OUT endpoints */
-+ ddesc_iso[i].actual_length = ddesc_iso[i].length -
-+ dwcep->desc_addr[i].status.b_iso_out.rxbytes;
-+ ddesc_iso[i].status =
-+ dwcep->desc_addr[i].status.b_iso_out.rxsts;
-+ }
-+ }
-+
-+ DWC_SPINUNLOCK(ep->pcd->lock);
-+
-+ /* Call the completion function in the non-portable logic */
-+ ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0,
-+ &req->ext_req);
-+
-+ DWC_SPINLOCK(ep->pcd->lock);
-+
-+ /* Free the request - specific freeing needed for extended request object */
-+ dwc_pcd_xiso_ereq_free(ep, req);
-+
-+ /* Start the next request */
-+ dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep);
-+
-+ return;
-+}
-+
-+/**
-+ * Create and initialize the Isoc pkt descriptors of the extended request.
-+ *
-+ */
-+static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req,
-+ void *ereq_nonport,
-+ int atomic_alloc)
-+{
-+ struct dwc_iso_xreq_port *ereq = NULL;
-+ struct dwc_iso_xreq_port *req_mapped = NULL;
-+ struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */
-+ uint32_t pkt_count;
-+ int i;
-+
-+ ereq = &req->ext_req;
-+ req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport;
-+ pkt_count = req_mapped->pio_pkt_count;
-+
-+ /* Create the isoc descs */
-+ if (atomic_alloc) {
-+ ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count);
-+ } else {
-+ ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count);
-+ }
-+
-+ if (!ipds) {
-+ DWC_ERROR("Failed to allocate isoc descriptors");
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ /* Initialize the extended request fields */
-+ ereq->per_io_frame_descs = ipds;
-+ ereq->error_count = 0;
-+ ereq->pio_alloc_pkt_count = pkt_count;
-+ ereq->pio_pkt_count = pkt_count;
-+ ereq->tr_sub_flags = req_mapped->tr_sub_flags;
-+
-+ /* Init the Isoc descriptors */
-+ for (i = 0; i < pkt_count; i++) {
-+ ipds[i].length = req_mapped->per_io_frame_descs[i].length;
-+ ipds[i].offset = req_mapped->per_io_frame_descs[i].offset;
-+ ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */
-+ ipds[i].actual_length =
-+ req_mapped->per_io_frame_descs[i].actual_length;
-+ }
-+
-+ return 0;
-+}
-+
-+static void prn_ext_request(struct dwc_iso_xreq_port *ereq)
-+{
-+ struct dwc_iso_pkt_desc_port *xfd = NULL;
-+ int i;
-+
-+ DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs);
-+ DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags);
-+ DWC_DEBUG("error_count=%d", ereq->error_count);
-+ DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count);
-+ DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count);
-+ DWC_DEBUG("res=%d", ereq->res);
-+
-+ for (i = 0; i < ereq->pio_pkt_count; i++) {
-+ xfd = &ereq->per_io_frame_descs[0];
-+ DWC_DEBUG("FD #%d", i);
-+
-+ DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length);
-+ DWC_DEBUG("xfd->length=%d", xfd->length);
-+ DWC_DEBUG("xfd->offset=%d", xfd->offset);
-+ DWC_DEBUG("xfd->status=%d", xfd->status);
-+ }
-+}
-+
-+/**
-+ *
-+ */
-+int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
-+ int zero, void *req_handle, int atomic_alloc,
-+ void *ereq_nonport)
-+{
-+ dwc_otg_pcd_request_t *req = NULL;
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_irqflags_t flags;
-+ int res;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+ if (!ep) {
-+ DWC_WARN("bad ep\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ /* We support this extension only for DDMA mode */
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
-+ if (!GET_CORE_IF(pcd)->dma_desc_enable)
-+ return -DWC_E_INVALID;
-+
-+ /* Create a dwc_otg_pcd_request_t object */
-+ if (atomic_alloc) {
-+ req = DWC_ALLOC_ATOMIC(sizeof(*req));
-+ } else {
-+ req = DWC_ALLOC(sizeof(*req));
-+ }
-+
-+ if (!req) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+
-+ /* Create the Isoc descs for this request which shall be the exact match
-+ * of the structure sent to us from the non-portable logic */
-+ res =
-+ dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc);
-+ if (res) {
-+ DWC_WARN("Failed to init the Isoc descriptors");
-+ DWC_FREE(req);
-+ return res;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+
-+ DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
-+ req->buf = buf;
-+ req->dma = dma_buf;
-+ req->length = buflen;
-+ req->sent_zlp = zero;
-+ req->priv = req_handle;
-+
-+ //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+ ep->dwc_ep.dma_addr = dma_buf;
-+ ep->dwc_ep.start_xfer_buff = buf;
-+ ep->dwc_ep.xfer_buff = buf;
-+ ep->dwc_ep.xfer_len = 0;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = buflen;
-+
-+ /* Add this request to the tail */
-+ DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
-+ ep->dwc_ep.xiso_queued_xfers++;
-+
-+//DWC_DEBUG("CP_0");
-+//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags);
-+//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport);
-+//prn_ext_request(&req->ext_req);
-+
-+ //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+ /* If the req->status == ASAP then check if there is any active transfer
-+ * for this endpoint. If no active transfers, then get the first entry
-+ * from the queue and start that transfer
-+ */
-+ if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) {
-+ res = dwc_otg_pcd_xiso_start_next_request(pcd, ep);
-+ if (res) {
-+ DWC_WARN("Failed to start the next Isoc transfer");
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ DWC_FREE(req);
-+ return res;
-+ }
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ return 0;
-+}
-+
-+#endif
-+/* END ifdef DWC_UTE_PER_IO ***************************************************/
-+int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
-+ int zero, void *req_handle, int atomic_alloc)
-+{
-+ dwc_irqflags_t flags;
-+ dwc_otg_pcd_request_t *req;
-+ dwc_otg_pcd_ep_t *ep;
-+ uint32_t max_transfer;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+ if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
-+ DWC_WARN("bad ep\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (atomic_alloc) {
-+ req = DWC_ALLOC_ATOMIC(sizeof(*req));
-+ } else {
-+ req = DWC_ALLOC(sizeof(*req));
-+ }
-+
-+ if (!req) {
-+ return -DWC_E_NO_MEMORY;
-+ }
-+ DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
-+ if (!GET_CORE_IF(pcd)->core_params->opt) {
-+ if (ep->dwc_ep.num != 0) {
-+ DWC_ERROR("queue req %p, len %d buf %p\n",
-+ req_handle, buflen, buf);
-+ }
-+ }
-+
-+ req->buf = buf;
-+ req->dma = dma_buf;
-+ req->length = buflen;
-+ req->sent_zlp = zero;
-+ req->priv = req_handle;
-+ req->dw_align_buf = NULL;
-+ if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable
-+ && !GET_CORE_IF(pcd)->dma_desc_enable)
-+ req->dw_align_buf = DWC_DMA_ALLOC(buflen,
-+ &req->dw_align_buf_dma);
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+
-+ /*
-+ * After adding request to the queue for IN ISOC wait for In Token Received
-+ * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token
-+ * Received when EP is disabled interrupt to obtain starting microframe
-+ * (odd/even) start transfer
-+ */
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ if (req != 0) {
-+ depctl_data_t depctl = {.d32 =
-+ DWC_READ_REG32(&pcd->core_if->dev_if->
-+ in_ep_regs[ep->dwc_ep.num]->
-+ diepctl) };
-+ ++pcd->request_pending;
-+
-+ DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
-+ if (ep->dwc_ep.is_in) {
-+ depctl.b.cnak = 1;
-+ DWC_WRITE_REG32(&pcd->core_if->dev_if->
-+ in_ep_regs[ep->dwc_ep.num]->
-+ diepctl, depctl.d32);
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ }
-+ return 0;
-+ }
-+
-+ /*
-+ * For EP0 IN without premature status, zlp is required?
-+ */
-+ if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
-+ DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
-+ //_req->zero = 1;
-+ }
-+
-+ /* Start the transfer */
-+ if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
-+ /* EP0 Transfer? */
-+ if (ep->dwc_ep.num == 0) {
-+ switch (pcd->ep0state) {
-+ case EP0_IN_DATA_PHASE:
-+ DWC_DEBUGPL(DBG_PCD,
-+ "%s ep0: EP0_IN_DATA_PHASE\n",
-+ __func__);
-+ break;
-+
-+ case EP0_OUT_DATA_PHASE:
-+ DWC_DEBUGPL(DBG_PCD,
-+ "%s ep0: EP0_OUT_DATA_PHASE\n",
-+ __func__);
-+ if (pcd->request_config) {
-+ /* Complete STATUS PHASE */
-+ ep->dwc_ep.is_in = 1;
-+ pcd->ep0state = EP0_IN_STATUS_PHASE;
-+ }
-+ break;
-+
-+ case EP0_IN_STATUS_PHASE:
-+ DWC_DEBUGPL(DBG_PCD,
-+ "%s ep0: EP0_IN_STATUS_PHASE\n",
-+ __func__);
-+ break;
-+
-+ default:
-+ DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
-+ pcd->ep0state);
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ return -DWC_E_SHUTDOWN;
-+ }
-+
-+ ep->dwc_ep.dma_addr = dma_buf;
-+ ep->dwc_ep.start_xfer_buff = buf;
-+ ep->dwc_ep.xfer_buff = buf;
-+ ep->dwc_ep.xfer_len = buflen;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
-+
-+ if (zero) {
-+ if ((ep->dwc_ep.xfer_len %
-+ ep->dwc_ep.maxpacket == 0)
-+ && (ep->dwc_ep.xfer_len != 0)) {
-+ ep->dwc_ep.sent_zlp = 1;
-+ }
-+
-+ }
-+
-+ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
-+ &ep->dwc_ep);
-+ } // non-ep0 endpoints
-+ else {
-+#ifdef DWC_UTE_CFI
-+ if (ep->dwc_ep.buff_mode != BM_STANDARD) {
-+ /* store the request length */
-+ ep->dwc_ep.cfi_req_len = buflen;
-+ pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
-+ ep, req);
-+ } else {
-+#endif
-+ max_transfer =
-+ GET_CORE_IF(ep->pcd)->core_params->
-+ max_transfer_size;
-+
-+ /* Setup and start the Transfer */
-+ if (req->dw_align_buf){
-+ if (ep->dwc_ep.is_in)
-+ dwc_memcpy(req->dw_align_buf,
-+ buf, buflen);
-+ ep->dwc_ep.dma_addr =
-+ req->dw_align_buf_dma;
-+ ep->dwc_ep.start_xfer_buff =
-+ req->dw_align_buf;
-+ ep->dwc_ep.xfer_buff =
-+ req->dw_align_buf;
-+ } else {
-+ ep->dwc_ep.dma_addr = dma_buf;
-+ ep->dwc_ep.start_xfer_buff = buf;
-+ ep->dwc_ep.xfer_buff = buf;
-+ }
-+ ep->dwc_ep.xfer_len = 0;
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = buflen;
-+
-+ ep->dwc_ep.maxxfer = max_transfer;
-+ if (GET_CORE_IF(pcd)->dma_desc_enable) {
-+ uint32_t out_max_xfer =
-+ DDMA_MAX_TRANSFER_SIZE -
-+ (DDMA_MAX_TRANSFER_SIZE % 4);
-+ if (ep->dwc_ep.is_in) {
-+ if (ep->dwc_ep.maxxfer >
-+ DDMA_MAX_TRANSFER_SIZE) {
-+ ep->dwc_ep.maxxfer =
-+ DDMA_MAX_TRANSFER_SIZE;
-+ }
-+ } else {
-+ if (ep->dwc_ep.maxxfer >
-+ out_max_xfer) {
-+ ep->dwc_ep.maxxfer =
-+ out_max_xfer;
-+ }
-+ }
-+ }
-+ if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
-+ ep->dwc_ep.maxxfer -=
-+ (ep->dwc_ep.maxxfer %
-+ ep->dwc_ep.maxpacket);
-+ }
-+
-+ if (zero) {
-+ if ((ep->dwc_ep.total_len %
-+ ep->dwc_ep.maxpacket == 0)
-+ && (ep->dwc_ep.total_len != 0)) {
-+ ep->dwc_ep.sent_zlp = 1;
-+ }
-+ }
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
-+ &ep->dwc_ep);
-+ }
-+ }
-+
-+ if (req != 0) {
-+ ++pcd->request_pending;
-+ DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
-+ if (ep->dwc_ep.is_in && ep->stopped
-+ && !(GET_CORE_IF(pcd)->dma_enable)) {
-+ /** @todo NGS Create a function for this. */
-+ diepmsk_data_t diepmsk = {.d32 = 0 };
-+ diepmsk.b.intktxfemp = 1;
-+ if (GET_CORE_IF(pcd)->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
-+ dev_if->dev_global_regs->diepeachintmsk
-+ [ep->dwc_ep.num], 0,
-+ diepmsk.d32);
-+ } else {
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->
-+ dev_if->dev_global_regs->
-+ diepmsk, 0, diepmsk.d32);
-+ }
-+
-+ }
-+ }
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+ return 0;
-+}
-+
-+int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle)
-+{
-+ dwc_irqflags_t flags;
-+ dwc_otg_pcd_request_t *req;
-+ dwc_otg_pcd_ep_t *ep;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+ if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) {
-+ DWC_WARN("bad argument\n");
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+
-+ /* make sure it's actually queued on this endpoint */
-+ DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
-+ if (req->priv == (void *)req_handle) {
-+ break;
-+ }
-+ }
-+
-+ if (req->priv != (void *)req_handle) {
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
-+ dwc_otg_request_done(ep, req, -DWC_E_RESTART);
-+ } else {
-+ req = NULL;
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+ return req ? 0 : -DWC_E_SHUTDOWN;
-+
-+}
-+
-+/**
-+ * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests
-+ *
-+ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
-+ * requests. If the gadget driver clears the halt status, it will
-+ * automatically unwedge the endpoint.
-+ *
-+ * Returns zero on success, else negative DWC error code.
-+ */
-+int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_irqflags_t flags;
-+ int retval = 0;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+
-+ if ((!ep->desc && ep != &pcd->ep0) ||
-+ (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
-+ DWC_WARN("%s, bad ep\n", __func__);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
-+ ep->dwc_ep.is_in ? "IN" : "OUT");
-+ retval = -DWC_E_AGAIN;
-+ } else {
-+ /* This code needs to be reviewed */
-+ if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
-+ dtxfsts_data_t txstatus;
-+ fifosize_data_t txfifosize;
-+
-+ txfifosize.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->
-+ core_global_regs->dtxfsiz[ep->dwc_ep.
-+ tx_fifo_num]);
-+ txstatus.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->
-+ dev_if->in_ep_regs[ep->dwc_ep.num]->
-+ dtxfsts);
-+
-+ if (txstatus.b.txfspcavail < txfifosize.b.depth) {
-+ DWC_WARN("%s() Data In Tx Fifo\n", __func__);
-+ retval = -DWC_E_AGAIN;
-+ } else {
-+ if (ep->dwc_ep.num == 0) {
-+ pcd->ep0state = EP0_STALL;
-+ }
-+
-+ ep->stopped = 1;
-+ dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
-+ &ep->dwc_ep);
-+ }
-+ } else {
-+ if (ep->dwc_ep.num == 0) {
-+ pcd->ep0state = EP0_STALL;
-+ }
-+
-+ ep->stopped = 1;
-+ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
-+ }
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+ return retval;
-+}
-+
-+int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_irqflags_t flags;
-+ int retval = 0;
-+
-+ ep = get_ep_from_handle(pcd, ep_handle);
-+
-+ if (!ep || (!ep->desc && ep != &pcd->ep0) ||
-+ (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
-+ DWC_WARN("%s, bad ep\n", __func__);
-+ return -DWC_E_INVALID;
-+ }
-+
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
-+ ep->dwc_ep.is_in ? "IN" : "OUT");
-+ retval = -DWC_E_AGAIN;
-+ } else if (value == 0) {
-+ dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
-+ } else if (value == 1) {
-+ if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
-+ dtxfsts_data_t txstatus;
-+ fifosize_data_t txfifosize;
-+
-+ txfifosize.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->
-+ dtxfsiz[ep->dwc_ep.tx_fifo_num]);
-+ txstatus.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
-+ in_ep_regs[ep->dwc_ep.num]->dtxfsts);
-+
-+ if (txstatus.b.txfspcavail < txfifosize.b.depth) {
-+ DWC_WARN("%s() Data In Tx Fifo\n", __func__);
-+ retval = -DWC_E_AGAIN;
-+ } else {
-+ if (ep->dwc_ep.num == 0) {
-+ pcd->ep0state = EP0_STALL;
-+ }
-+
-+ ep->stopped = 1;
-+ dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
-+ &ep->dwc_ep);
-+ }
-+ } else {
-+ if (ep->dwc_ep.num == 0) {
-+ pcd->ep0state = EP0_STALL;
-+ }
-+
-+ ep->stopped = 1;
-+ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
-+ }
-+ } else if (value == 2) {
-+ ep->dwc_ep.stall_clear_flag = 0;
-+ } else if (value == 3) {
-+ ep->dwc_ep.stall_clear_flag = 1;
-+ }
-+
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function initiates remote wakeup of the host from suspend state.
-+ */
-+void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
-+{
-+ dctl_data_t dctl = { 0 };
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dsts_data_t dsts;
-+
-+ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+ if (!dsts.b.suspsts) {
-+ DWC_WARN("Remote wakeup while is not in suspend state\n");
-+ }
-+ /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
-+ if (pcd->remote_wakeup_enable) {
-+ if (set) {
-+
-+ if (core_if->adp_enable) {
-+ gpwrdn_data_t gpwrdn;
-+
-+ dwc_otg_adp_probe_stop(core_if);
-+
-+ /* Mask SRP detected interrupt from Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.srp_det_msk = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->gpwrdn,
-+ gpwrdn.d32, 0);
-+
-+ /* Disable Power Down Logic */
-+ gpwrdn.d32 = 0;
-+ gpwrdn.b.pmuactv = 1;
-+ DWC_MODIFY_REG32(&core_if->
-+ core_global_regs->gpwrdn,
-+ gpwrdn.d32, 0);
-+
-+ /*
-+ * Initialize the Core for Device mode.
-+ */
-+ core_if->op_state = B_PERIPHERAL;
-+ dwc_otg_core_init(core_if);
-+ dwc_otg_enable_global_interrupts(core_if);
-+ cil_pcd_start(core_if);
-+
-+ dwc_otg_initiate_srp(core_if);
-+ }
-+
-+ dctl.b.rmtwkupsig = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ dctl, 0, dctl.d32);
-+ DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
-+
-+ dwc_mdelay(2);
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ dctl, dctl.d32, 0);
-+ DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
-+ }
-+ } else {
-+ DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
-+ }
-+}
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+/**
-+ * This function initiates remote wakeup of the host from L1 sleep state.
-+ */
-+void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
-+{
-+ glpmcfg_data_t lpmcfg;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+
-+ /* Check if we are in L1 state */
-+ if (!lpmcfg.b.prt_sleep_sts) {
-+ DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
-+ return;
-+ }
-+
-+ /* Check if host allows remote wakeup */
-+ if (!lpmcfg.b.rem_wkup_en) {
-+ DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
-+ return;
-+ }
-+
-+ /* Check if Resume OK */
-+ if (!lpmcfg.b.sleep_state_resumeok) {
-+ DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
-+ return;
-+ }
-+
-+ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
-+ lpmcfg.b.en_utmi_sleep = 0;
-+ lpmcfg.b.hird_thres &= (~(1 << 4));
-+ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
-+
-+ if (set) {
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dctl.b.rmtwkupsig = 1;
-+ /* Set RmtWkUpSig bit to start remote wakup signaling.
-+ * Hardware will automatically clear this bit.
-+ */
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl,
-+ 0, dctl.d32);
-+ DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
-+ }
-+
-+}
-+#endif
-+
-+/**
-+ * Performs remote wakeup.
-+ */
-+void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_irqflags_t flags;
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ if (core_if->lx_state == DWC_OTG_L1) {
-+ dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
-+ } else {
-+#endif
-+ dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ }
-+#endif
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+ }
-+ return;
-+}
-+
-+void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dctl_data_t dctl = { 0 };
-+
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ dctl.b.sftdiscon = 1;
-+ DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs);
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
-+ dwc_udelay(no_of_usecs);
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0);
-+
-+ } else{
-+ DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n");
-+ }
-+ return;
-+
-+}
-+
-+int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
-+{
-+ dsts_data_t dsts;
-+ gotgctl_data_t gotgctl;
-+
-+ /*
-+ * This function starts the Protocol if no session is in progress. If
-+ * a session is already in progress, but the device is suspended,
-+ * remote wakeup signaling is started.
-+ */
-+
-+ /* Check if valid session */
-+ gotgctl.d32 =
-+ DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
-+ if (gotgctl.b.bsesvld) {
-+ /* Check if suspend state */
-+ dsts.d32 =
-+ DWC_READ_REG32(&
-+ (GET_CORE_IF(pcd)->dev_if->
-+ dev_global_regs->dsts));
-+ if (dsts.b.suspsts) {
-+ dwc_otg_pcd_remote_wakeup(pcd, 1);
-+ }
-+ } else {
-+ dwc_otg_pcd_initiate_srp(pcd);
-+ }
-+
-+ return 0;
-+
-+}
-+
-+/**
-+ * Start the SRP timer to detect when the SRP does not complete within
-+ * 6 seconds.
-+ *
-+ * @param pcd the pcd structure.
-+ */
-+void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_irqflags_t flags;
-+ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
-+ dwc_otg_initiate_srp(GET_CORE_IF(pcd));
-+ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
-+}
-+
-+int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
-+{
-+ return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
-+}
-+
-+int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
-+{
-+ return GET_CORE_IF(pcd)->core_params->lpm_enable;
-+}
-+
-+uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
-+{
-+ return pcd->b_hnp_enable;
-+}
-+
-+uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
-+{
-+ return pcd->a_hnp_support;
-+}
-+
-+uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
-+{
-+ return pcd->a_alt_hnp_support;
-+}
-+
-+int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
-+{
-+ return pcd->remote_wakeup_enable;
-+}
-+
-+#endif /* DWC_HOST_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,266 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
-+ * $Revision: #48 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_HOST_ONLY
-+#if !defined(__DWC_PCD_H__)
-+#define __DWC_PCD_H__
-+
-+#include "dwc_otg_os_dep.h"
-+#include "usb.h"
-+#include "dwc_otg_cil.h"
-+#include "dwc_otg_pcd_if.h"
-+struct cfiobject;
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the structures, constants, and interfaces for
-+ * the Perpherial Contoller Driver (PCD).
-+ *
-+ * The Peripheral Controller Driver (PCD) for Linux will implement the
-+ * Gadget API, so that the existing Gadget drivers can be used. For
-+ * the Mass Storage Function driver the File-backed USB Storage Gadget
-+ * (FBS) driver will be used. The FBS driver supports the
-+ * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
-+ * transports.
-+ *
-+ */
-+
-+/** Invalid DMA Address */
-+#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0)
-+
-+/** Max Transfer size for any EP */
-+#define DDMA_MAX_TRANSFER_SIZE 65535
-+
-+/**
-+ * Get the pointer to the core_if from the pcd pointer.
-+ */
-+#define GET_CORE_IF( _pcd ) (_pcd->core_if)
-+
-+/**
-+ * States of EP0.
-+ */
-+typedef enum ep0_state {
-+ EP0_DISCONNECT, /* no host */
-+ EP0_IDLE,
-+ EP0_IN_DATA_PHASE,
-+ EP0_OUT_DATA_PHASE,
-+ EP0_IN_STATUS_PHASE,
-+ EP0_OUT_STATUS_PHASE,
-+ EP0_STALL,
-+} ep0state_e;
-+
-+/** Fordward declaration.*/
-+struct dwc_otg_pcd;
-+
-+/** DWC_otg iso request structure.
-+ *
-+ */
-+typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
-+
-+#ifdef DWC_UTE_PER_IO
-+
-+/**
-+ * This shall be the exact analogy of the same type structure defined in the
-+ * usb_gadget.h. Each descriptor contains
-+ */
-+struct dwc_iso_pkt_desc_port {
-+ uint32_t offset;
-+ uint32_t length; /* expected length */
-+ uint32_t actual_length;
-+ uint32_t status;
-+};
-+
-+struct dwc_iso_xreq_port {
-+ /** transfer/submission flag */
-+ uint32_t tr_sub_flags;
-+ /** Start the request ASAP */
-+#define DWC_EREQ_TF_ASAP 0x00000002
-+ /** Just enqueue the request w/o initiating a transfer */
-+#define DWC_EREQ_TF_ENQUEUE 0x00000004
-+
-+ /**
-+ * count of ISO packets attached to this request - shall
-+ * not exceed the pio_alloc_pkt_count
-+ */
-+ uint32_t pio_pkt_count;
-+ /** count of ISO packets allocated for this request */
-+ uint32_t pio_alloc_pkt_count;
-+ /** number of ISO packet errors */
-+ uint32_t error_count;
-+ /** reserved for future extension */
-+ uint32_t res;
-+ /** Will be allocated and freed in the UTE gadget and based on the CFC value */
-+ struct dwc_iso_pkt_desc_port *per_io_frame_descs;
-+};
-+#endif
-+/** DWC_otg request structure.
-+ * This structure is a list of requests.
-+ */
-+typedef struct dwc_otg_pcd_request {
-+ void *priv;
-+ void *buf;
-+ dwc_dma_t dma;
-+ uint32_t length;
-+ uint32_t actual;
-+ unsigned sent_zlp:1;
-+ /**
-+ * Used instead of original buffer if
-+ * it(physical address) is not dword-aligned.
-+ **/
-+ uint8_t *dw_align_buf;
-+ dwc_dma_t dw_align_buf_dma;
-+
-+ DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
-+#ifdef DWC_UTE_PER_IO
-+ struct dwc_iso_xreq_port ext_req;
-+ //void *priv_ereq_nport; /* */
-+#endif
-+} dwc_otg_pcd_request_t;
-+
-+DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
-+
-+/** PCD EP structure.
-+ * This structure describes an EP, there is an array of EPs in the PCD
-+ * structure.
-+ */
-+typedef struct dwc_otg_pcd_ep {
-+ /** USB EP Descriptor */
-+ const usb_endpoint_descriptor_t *desc;
-+
-+ /** queue of dwc_otg_pcd_requests. */
-+ struct req_list queue;
-+ unsigned stopped:1;
-+ unsigned disabling:1;
-+ unsigned dma:1;
-+ unsigned queue_sof:1;
-+
-+#ifdef DWC_EN_ISOC
-+ /** ISOC req handle passed */
-+ void *iso_req_handle;
-+#endif //_EN_ISOC_
-+
-+ /** DWC_otg ep data. */
-+ dwc_ep_t dwc_ep;
-+
-+ /** Pointer to PCD */
-+ struct dwc_otg_pcd *pcd;
-+
-+ void *priv;
-+} dwc_otg_pcd_ep_t;
-+
-+/** DWC_otg PCD Structure.
-+ * This structure encapsulates the data for the dwc_otg PCD.
-+ */
-+struct dwc_otg_pcd {
-+ const struct dwc_otg_pcd_function_ops *fops;
-+ /** The DWC otg device pointer */
-+ struct dwc_otg_device *otg_dev;
-+ /** Core Interface */
-+ dwc_otg_core_if_t *core_if;
-+ /** State of EP0 */
-+ ep0state_e ep0state;
-+ /** EP0 Request is pending */
-+ unsigned ep0_pending:1;
-+ /** Indicates when SET CONFIGURATION Request is in process */
-+ unsigned request_config:1;
-+ /** The state of the Remote Wakeup Enable. */
-+ unsigned remote_wakeup_enable:1;
-+ /** The state of the B-Device HNP Enable. */
-+ unsigned b_hnp_enable:1;
-+ /** The state of A-Device HNP Support. */
-+ unsigned a_hnp_support:1;
-+ /** The state of the A-Device Alt HNP support. */
-+ unsigned a_alt_hnp_support:1;
-+ /** Count of pending Requests */
-+ unsigned request_pending;
-+
-+ /** SETUP packet for EP0
-+ * This structure is allocated as a DMA buffer on PCD initialization
-+ * with enough space for up to 3 setup packets.
-+ */
-+ union {
-+ usb_device_request_t req;
-+ uint32_t d32[2];
-+ } *setup_pkt;
-+
-+ dwc_dma_t setup_pkt_dma_handle;
-+
-+ /* Additional buffer and flag for CTRL_WR premature case */
-+ uint8_t *backup_buf;
-+ unsigned data_terminated;
-+
-+ /** 2-byte dma buffer used to return status from GET_STATUS */
-+ uint16_t *status_buf;
-+ dwc_dma_t status_buf_dma_handle;
-+
-+ /** EP0 */
-+ dwc_otg_pcd_ep_t ep0;
-+
-+ /** Array of IN EPs. */
-+ dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
-+ /** Array of OUT EPs. */
-+ dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
-+ /** number of valid EPs in the above array. */
-+// unsigned num_eps : 4;
-+ dwc_spinlock_t *lock;
-+
-+ /** Tasklet to defer starting of TEST mode transmissions until
-+ * Status Phase has been completed.
-+ */
-+ dwc_tasklet_t *test_mode_tasklet;
-+
-+ /** Tasklet to delay starting of xfer in DMA mode */
-+ dwc_tasklet_t *start_xfer_tasklet;
-+
-+ /** The test mode to enter when the tasklet is executed. */
-+ unsigned test_mode;
-+ /** The cfi_api structure that implements most of the CFI API
-+ * and OTG specific core configuration functionality
-+ */
-+#ifdef DWC_UTE_CFI
-+ struct cfiobject *cfi;
-+#endif
-+
-+};
-+
-+//FIXME this functions should be static, and this prototypes should be removed
-+extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
-+extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
-+ dwc_otg_pcd_request_t * req, int32_t status);
-+
-+void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
-+ void *req_handle);
-+
-+extern void do_test_mode(void *data);
-+#endif
-+#endif /* DWC_HOST_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,360 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
-+ * $Revision: #11 $
-+ * $Date: 2011/10/26 $
-+ * $Change: 1873028 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_HOST_ONLY
-+
-+#if !defined(__DWC_PCD_IF_H__)
-+#define __DWC_PCD_IF_H__
-+
-+//#include "dwc_os.h"
-+#include "dwc_otg_core_if.h"
-+
-+/** @file
-+ * This file defines DWC_OTG PCD Core API.
-+ */
-+
-+struct dwc_otg_pcd;
-+typedef struct dwc_otg_pcd dwc_otg_pcd_t;
-+
-+/** Maxpacket size for EP0 */
-+#define MAX_EP0_SIZE 64
-+/** Maxpacket size for any EP */
-+#define MAX_PACKET_SIZE 1024
-+
-+/** @name Function Driver Callbacks */
-+/** @{ */
-+
-+/** This function will be called whenever a previously queued request has
-+ * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a
-+ * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset,
-+ * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid
-+ * parameters. */
-+typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle, int32_t status,
-+ uint32_t actual);
-+/**
-+ * This function will be called whenever a previousle queued ISOC request has
-+ * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count
-+ * function.
-+ * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_*
-+ * functions.
-+ */
-+typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle, int proc_buf_num);
-+/** This function should handle any SETUP request that cannot be handled by the
-+ * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any
-+ * class-specific requests, etc. The function must non-blocking.
-+ *
-+ * Returns 0 on success.
-+ * Returns -DWC_E_NOT_SUPPORTED if the request is not supported.
-+ * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes.
-+ * Returns -DWC_E_SHUTDOWN on any other error. */
-+typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
-+/** This is called whenever the device has been disconnected. The function
-+ * driver should take appropriate action to clean up all pending requests in the
-+ * PCD Core, remove all endpoints (except ep0), and initialize back to reset
-+ * state. */
-+typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
-+/** This function is called when device has been connected. */
-+typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
-+/** This function is called when device has been suspended */
-+typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
-+/** This function is called when device has received LPM tokens, i.e.
-+ * device has been sent to sleep state. */
-+typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
-+/** This function is called when device has been resumed
-+ * from suspend(L2) or L1 sleep state. */
-+typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
-+/** This function is called whenever hnp params has been changed.
-+ * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions
-+ * to get hnp parameters. */
-+typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
-+/** This function is called whenever USB RESET is detected. */
-+typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
-+
-+typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
-+
-+/**
-+ *
-+ * @param ep_handle Void pointer to the usb_ep structure
-+ * @param ereq_port Pointer to the extended request structure created in the
-+ * portable part.
-+ */
-+typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle, int32_t status,
-+ void *ereq_port);
-+/** Function Driver Ops Data Structure */
-+struct dwc_otg_pcd_function_ops {
-+ dwc_connect_cb_t connect;
-+ dwc_disconnect_cb_t disconnect;
-+ dwc_setup_cb_t setup;
-+ dwc_completion_cb_t complete;
-+ dwc_isoc_completion_cb_t isoc_complete;
-+ dwc_suspend_cb_t suspend;
-+ dwc_sleep_cb_t sleep;
-+ dwc_resume_cb_t resume;
-+ dwc_reset_cb_t reset;
-+ dwc_hnp_params_changed_cb_t hnp_changed;
-+ cfi_setup_cb_t cfi_setup;
-+#ifdef DWC_UTE_PER_IO
-+ xiso_completion_cb_t xisoc_complete;
-+#endif
-+};
-+/** @} */
-+
-+/** @name Function Driver Functions */
-+/** @{ */
-+
-+/** Call this function to get pointer on dwc_otg_pcd_t,
-+ * this pointer will be used for all PCD API functions.
-+ *
-+ * @param core_if The DWC_OTG Core
-+ */
-+extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
-+
-+/** Frees PCD allocated by dwc_otg_pcd_init
-+ *
-+ * @param pcd The PCD
-+ */
-+extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
-+
-+/** Call this to bind the function driver to the PCD Core.
-+ *
-+ * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
-+ * @param fops The Function Driver Ops data structure containing pointers to all callbacks.
-+ */
-+extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
-+ const struct dwc_otg_pcd_function_ops *fops);
-+
-+/** Enables an endpoint for use. This function enables an endpoint in
-+ * the PCD. The endpoint is described by the ep_desc which has the
-+ * same format as a USB ep descriptor. The ep_handle parameter is used to refer
-+ * to the endpoint from other API functions and in callbacks. Normally this
-+ * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the
-+ * core for that interface.
-+ *
-+ * Returns -DWC_E_INVALID if invalid parameters were passed.
-+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
-+ * Returns 0 on success.
-+ *
-+ * @param pcd The PCD
-+ * @param ep_desc Endpoint descriptor
-+ * @param usb_ep Handle on endpoint, that will be used to identify endpoint.
-+ */
-+extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
-+ const uint8_t * ep_desc, void *usb_ep);
-+
-+/** Disable the endpoint referenced by ep_handle.
-+ *
-+ * Returns -DWC_E_INVALID if invalid parameters were passed.
-+ * Returns -DWC_E_SHUTDOWN if any other error occurred.
-+ * Returns 0 on success. */
-+extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
-+
-+/** Queue a data transfer request on the endpoint referenced by ep_handle.
-+ * After the transfer is completes, the complete callback will be called with
-+ * the request status.
-+ *
-+ * @param pcd The PCD
-+ * @param ep_handle The handle of the endpoint
-+ * @param buf The buffer for the data
-+ * @param dma_buf The DMA buffer for the data
-+ * @param buflen The length of the data transfer
-+ * @param zero Specifies whether to send zero length last packet.
-+ * @param req_handle Set this handle to any value to use to reference this
-+ * request in the ep_dequeue function or from the complete callback
-+ * @param atomic_alloc If driver need to perform atomic allocations
-+ * for internal data structures.
-+ *
-+ * Returns -DWC_E_INVALID if invalid parameters were passed.
-+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
-+ * Returns 0 on success. */
-+extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ uint8_t * buf, dwc_dma_t dma_buf,
-+ uint32_t buflen, int zero, void *req_handle,
-+ int atomic_alloc);
-+#ifdef DWC_UTE_PER_IO
-+/**
-+ *
-+ * @param ereq_nonport Pointer to the extended request part of the
-+ * usb_request structure defined in usb_gadget.h file.
-+ */
-+extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ uint8_t * buf, dwc_dma_t dma_buf,
-+ uint32_t buflen, int zero,
-+ void *req_handle, int atomic_alloc,
-+ void *ereq_nonport);
-+
-+#endif
-+
-+/** De-queue the specified data transfer that has not yet completed.
-+ *
-+ * Returns -DWC_E_INVALID if invalid parameters were passed.
-+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
-+ * Returns 0 on success. */
-+extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle);
-+
-+/** Halt (STALL) an endpoint or clear it.
-+ *
-+ * Returns -DWC_E_INVALID if invalid parameters were passed.
-+ * Returns -DWC_E_SHUTDOWN if any other error ocurred.
-+ * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later
-+ * Returns 0 on success. */
-+extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
-+
-+/** This function */
-+extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle);
-+
-+/** This function should be called on every hardware interrupt */
-+extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
-+
-+/** This function returns current frame number */
-+extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
-+
-+/**
-+ * Start isochronous transfers on the endpoint referenced by ep_handle.
-+ * For isochronous transfers duble buffering is used.
-+ * After processing each of buffers comlete callback will be called with
-+ * status for each transaction.
-+ *
-+ * @param pcd The PCD
-+ * @param ep_handle The handle of the endpoint
-+ * @param buf0 The virtual address of first data buffer
-+ * @param buf1 The virtual address of second data buffer
-+ * @param dma0 The DMA address of first data buffer
-+ * @param dma1 The DMA address of second data buffer
-+ * @param sync_frame Data pattern frame number
-+ * @param dp_frame Data size for pattern frame
-+ * @param data_per_frame Data size for regular frame
-+ * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP.
-+ * @param buf_proc_intrvl Interval of ISOC Buffer processing
-+ * @param req_handle Handle of ISOC request
-+ * @param atomic_alloc Specefies whether to perform atomic allocation for
-+ * internal data structures.
-+ *
-+ * Returns -DWC_E_NO_MEMORY if there is no enough memory.
-+ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function.
-+ * Returns -DW_E_SHUTDOWN for any other error.
-+ * Returns 0 on success
-+ */
-+extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ uint8_t * buf0, uint8_t * buf1,
-+ dwc_dma_t dma0, dwc_dma_t dma1,
-+ int sync_frame, int dp_frame,
-+ int data_per_frame, int start_frame,
-+ int buf_proc_intrvl, void *req_handle,
-+ int atomic_alloc);
-+
-+/** Stop ISOC transfers on endpoint referenced by ep_handle.
-+ *
-+ * @param pcd The PCD
-+ * @param ep_handle The handle of the endpoint
-+ * @param req_handle Handle of ISOC request
-+ *
-+ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function
-+ * Returns 0 on success
-+ */
-+int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle);
-+
-+/** Get ISOC packet status.
-+ *
-+ * @param pcd The PCD
-+ * @param ep_handle The handle of the endpoint
-+ * @param iso_req_handle Isochronoush request handle
-+ * @param packet Number of packet
-+ * @param status Out parameter for returning status
-+ * @param actual Out parameter for returning actual length
-+ * @param offset Out parameter for returning offset
-+ *
-+ */
-+extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
-+ void *ep_handle,
-+ void *iso_req_handle, int packet,
-+ int *status, int *actual,
-+ int *offset);
-+
-+/** Get ISOC packet count.
-+ *
-+ * @param pcd The PCD
-+ * @param ep_handle The handle of the endpoint
-+ * @param iso_req_handle
-+ */
-+extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
-+ void *ep_handle,
-+ void *iso_req_handle);
-+
-+/** This function starts the SRP Protocol if no session is in progress. If
-+ * a session is already in progress, but the device is suspended,
-+ * remote wakeup signaling is started.
-+ */
-+extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
-+
-+/** This function returns 1 if LPM support is enabled, and 0 otherwise. */
-+extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
-+
-+/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */
-+extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
-+
-+/** Initiate SRP */
-+extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
-+
-+/** Starts remote wakeup signaling. */
-+extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
-+
-+/** Starts micorsecond soft disconnect. */
-+extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs);
-+/** This function returns whether device is dualspeed.*/
-+extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
-+
-+/** This function returns whether device is otg. */
-+extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
-+
-+/** These functions allow to get hnp parameters */
-+extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
-+extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
-+extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
-+
-+/** CFI specific Interface functions */
-+/** Allocate a cfi buffer */
-+extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
-+ dwc_dma_t * addr, size_t buflen,
-+ int flags);
-+
-+/******************************************************************************/
-+
-+/** @} */
-+
-+#endif /* __DWC_PCD_IF_H__ */
-+
-+#endif /* DWC_HOST_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,5147 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
-+ * $Revision: #116 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_HOST_ONLY
-+
-+#include "dwc_otg_pcd.h"
-+
-+#ifdef DWC_UTE_CFI
-+#include "dwc_otg_cfi.h"
-+#endif
-+
-+#ifdef DWC_UTE_PER_IO
-+extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep);
-+#endif
-+//#define PRINT_CFI_DMA_DESCS
-+
-+#define DEBUG_EP0
-+
-+/**
-+ * This function updates OTG.
-+ */
-+static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
-+{
-+
-+ if (reset) {
-+ pcd->b_hnp_enable = 0;
-+ pcd->a_hnp_support = 0;
-+ pcd->a_alt_hnp_support = 0;
-+ }
-+
-+ if (pcd->fops->hnp_changed) {
-+ pcd->fops->hnp_changed(pcd);
-+ }
-+}
-+
-+/** @file
-+ * This file contains the implementation of the PCD Interrupt handlers.
-+ *
-+ * The PCD handles the device interrupts. Many conditions can cause a
-+ * device interrupt. When an interrupt occurs, the device interrupt
-+ * service routine determines the cause of the interrupt and
-+ * dispatches handling to the appropriate function. These interrupt
-+ * handling functions are described below.
-+ * All interrupt registers are processed from LSB to MSB.
-+ */
-+
-+/**
-+ * This function prints the ep0 state for debug purposes.
-+ */
-+static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
-+{
-+#ifdef DEBUG
-+ char str[40];
-+
-+ switch (pcd->ep0state) {
-+ case EP0_DISCONNECT:
-+ dwc_strcpy(str, "EP0_DISCONNECT");
-+ break;
-+ case EP0_IDLE:
-+ dwc_strcpy(str, "EP0_IDLE");
-+ break;
-+ case EP0_IN_DATA_PHASE:
-+ dwc_strcpy(str, "EP0_IN_DATA_PHASE");
-+ break;
-+ case EP0_OUT_DATA_PHASE:
-+ dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
-+ break;
-+ case EP0_IN_STATUS_PHASE:
-+ dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
-+ break;
-+ case EP0_OUT_STATUS_PHASE:
-+ dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
-+ break;
-+ case EP0_STALL:
-+ dwc_strcpy(str, "EP0_STALL");
-+ break;
-+ default:
-+ dwc_strcpy(str, "EP0_INVALID");
-+ }
-+
-+ DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
-+#endif
-+}
-+
-+/**
-+ * This function calculate the size of the payload in the memory
-+ * for out endpoints and prints size for debug purposes(used in
-+ * 2.93a DevOutNak feature).
-+ */
-+static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep)
-+{
-+#ifdef DEBUG
-+ deptsiz_data_t deptsiz_init = {.d32 = 0 };
-+ deptsiz_data_t deptsiz_updt = {.d32 = 0 };
-+ int pack_num;
-+ unsigned payload;
-+
-+ deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num];
-+ deptsiz_updt.d32 =
-+ DWC_READ_REG32(&pcd->core_if->dev_if->
-+ out_ep_regs[ep->num]->doeptsiz);
-+ /* Payload will be */
-+ payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize;
-+ /* Packet count is decremented every time a packet
-+ * is written to the RxFIFO not in to the external memory
-+ * So, if payload == 0, then it means no packet was sent to ext memory*/
-+ pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt);
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "Payload for EP%d-%s\n",
-+ ep->num, (ep->is_in ? "IN" : "OUT"));
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "Number of transfered bytes = 0x%08x\n", payload);
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "Number of transfered packets = %d\n", pack_num);
-+#endif
-+}
-+
-+
-+#ifdef DWC_UTE_CFI
-+static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
-+ const uint8_t * epname, int descnum)
-+{
-+ CFI_INFO
-+ ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
-+ epname, descnum, ddesc->buf, ddesc->status.b.bytes,
-+ ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
-+ ddesc->status.b.bs);
-+}
-+#endif
-+
-+/**
-+ * This function returns pointer to in ep struct with number ep_num
-+ */
-+static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
-+{
-+ int i;
-+ int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
-+ if (ep_num == 0) {
-+ return &pcd->ep0;
-+ } else {
-+ for (i = 0; i < num_in_eps; ++i) {
-+ if (pcd->in_ep[i].dwc_ep.num == ep_num)
-+ return &pcd->in_ep[i];
-+ }
-+ return 0;
-+ }
-+}
-+
-+/**
-+ * This function returns pointer to out ep struct with number ep_num
-+ */
-+static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
-+{
-+ int i;
-+ int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
-+ if (ep_num == 0) {
-+ return &pcd->ep0;
-+ } else {
-+ for (i = 0; i < num_out_eps; ++i) {
-+ if (pcd->out_ep[i].dwc_ep.num == ep_num)
-+ return &pcd->out_ep[i];
-+ }
-+ return 0;
-+ }
-+}
-+
-+/**
-+ * This functions gets a pointer to an EP from the wIndex address
-+ * value of the control request.
-+ */
-+dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
-+{
-+ dwc_otg_pcd_ep_t *ep;
-+ uint32_t ep_num = UE_GET_ADDR(wIndex);
-+
-+ if (ep_num == 0) {
-+ ep = &pcd->ep0;
-+ } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */
-+ ep = &pcd->in_ep[ep_num - 1];
-+ } else {
-+ ep = &pcd->out_ep[ep_num - 1];
-+ }
-+
-+ return ep;
-+}
-+
-+/**
-+ * This function checks the EP request queue, if the queue is not
-+ * empty the next request is started.
-+ */
-+void start_next_request(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_otg_pcd_request_t *req = 0;
-+ uint32_t max_transfer =
-+ GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
-+
-+#ifdef DWC_UTE_CFI
-+ struct dwc_otg_pcd *pcd;
-+ pcd = ep->pcd;
-+#endif
-+
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+
-+#ifdef DWC_UTE_CFI
-+ if (ep->dwc_ep.buff_mode != BM_STANDARD) {
-+ ep->dwc_ep.cfi_req_len = req->length;
-+ pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
-+ } else {
-+#endif
-+ /* Setup and start the Transfer */
-+ if (req->dw_align_buf) {
-+ ep->dwc_ep.dma_addr = req->dw_align_buf_dma;
-+ ep->dwc_ep.start_xfer_buff = req->dw_align_buf;
-+ ep->dwc_ep.xfer_buff = req->dw_align_buf;
-+ } else {
-+ ep->dwc_ep.dma_addr = req->dma;
-+ ep->dwc_ep.start_xfer_buff = req->buf;
-+ ep->dwc_ep.xfer_buff = req->buf;
-+ }
-+ ep->dwc_ep.sent_zlp = 0;
-+ ep->dwc_ep.total_len = req->length;
-+ ep->dwc_ep.xfer_len = 0;
-+ ep->dwc_ep.xfer_count = 0;
-+
-+ ep->dwc_ep.maxxfer = max_transfer;
-+ if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
-+ uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
-+ - (DDMA_MAX_TRANSFER_SIZE % 4);
-+ if (ep->dwc_ep.is_in) {
-+ if (ep->dwc_ep.maxxfer >
-+ DDMA_MAX_TRANSFER_SIZE) {
-+ ep->dwc_ep.maxxfer =
-+ DDMA_MAX_TRANSFER_SIZE;
-+ }
-+ } else {
-+ if (ep->dwc_ep.maxxfer > out_max_xfer) {
-+ ep->dwc_ep.maxxfer =
-+ out_max_xfer;
-+ }
-+ }
-+ }
-+ if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
-+ ep->dwc_ep.maxxfer -=
-+ (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
-+ }
-+ if (req->sent_zlp) {
-+ if ((ep->dwc_ep.total_len %
-+ ep->dwc_ep.maxpacket == 0)
-+ && (ep->dwc_ep.total_len != 0)) {
-+ ep->dwc_ep.sent_zlp = 1;
-+ }
-+
-+ }
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
-+ } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ DWC_PRINTF("There are no more ISOC requests \n");
-+ ep->dwc_ep.frame_num = 0xFFFFFFFF;
-+ }
-+}
-+
-+/**
-+ * This function handles the SOF Interrupts. At this time the SOF
-+ * Interrupt is disabled.
-+ */
-+int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+
-+ gintsts_data_t gintsts;
-+
-+ DWC_DEBUGPL(DBG_PCD, "SOF\n");
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.sofintr = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This function handles the Rx Status Queue Level Interrupt, which
-+ * indicates that there is a least one packet in the Rx FIFO. The
-+ * packets are moved from the FIFO to memory, where they will be
-+ * processed when the Endpoint Interrupt Register indicates Transfer
-+ * Complete or SETUP Phase Done.
-+ *
-+ * Repeat the following until the Rx Status Queue is empty:
-+ * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
-+ * info
-+ * -# If Receive FIFO is empty then skip to step Clear the interrupt
-+ * and exit
-+ * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
-+ * SETUP data to the buffer
-+ * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
-+ * to the destination buffer
-+ */
-+int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ gintmsk_data_t gintmask = {.d32 = 0 };
-+ device_grxsts_data_t status;
-+ dwc_otg_pcd_ep_t *ep;
-+ gintsts_data_t gintsts;
-+#ifdef DEBUG
-+ static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
-+#endif
-+
-+ //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
-+ /* Disable the Rx Status Queue Level interrupt */
-+ gintmask.b.rxstsqlvl = 1;
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0);
-+
-+ /* Get the Status from the top of the FIFO */
-+ status.d32 = DWC_READ_REG32(&global_regs->grxstsp);
-+
-+ DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
-+ "pktsts:%x Frame:%d(0x%0x)\n",
-+ status.b.epnum, status.b.bcnt,
-+ dpid_str[status.b.dpid],
-+ status.b.pktsts, status.b.fn, status.b.fn);
-+ /* Get pointer to EP structure */
-+ ep = get_out_ep(pcd, status.b.epnum);
-+
-+ switch (status.b.pktsts) {
-+ case DWC_DSTS_GOUT_NAK:
-+ DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
-+ break;
-+ case DWC_STS_DATA_UPDT:
-+ DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
-+ if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
-+ /** @todo NGS Check for buffer overflow? */
-+ dwc_otg_read_packet(core_if,
-+ ep->dwc_ep.xfer_buff,
-+ status.b.bcnt);
-+ ep->dwc_ep.xfer_count += status.b.bcnt;
-+ ep->dwc_ep.xfer_buff += status.b.bcnt;
-+ }
-+ break;
-+ case DWC_STS_XFER_COMP:
-+ DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
-+ break;
-+ case DWC_DSTS_SETUP_COMP:
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
-+#endif
-+ break;
-+ case DWC_DSTS_SETUP_UPDT:
-+ dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD,
-+ "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
-+ pcd->setup_pkt->req.bmRequestType,
-+ pcd->setup_pkt->req.bRequest,
-+ UGETW(pcd->setup_pkt->req.wValue),
-+ UGETW(pcd->setup_pkt->req.wIndex),
-+ UGETW(pcd->setup_pkt->req.wLength));
-+#endif
-+ ep->dwc_ep.xfer_count += status.b.bcnt;
-+ break;
-+ default:
-+ DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
-+ status.b.pktsts);
-+ break;
-+ }
-+
-+ /* Enable the Rx Status Queue Level interrupt */
-+ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32);
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.rxstsqlvl = 1;
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
-+ return 1;
-+}
-+
-+/**
-+ * This function examines the Device IN Token Learning Queue to
-+ * determine the EP number of the last IN token received. This
-+ * implementation is for the Mass Storage device where there are only
-+ * 2 IN EPs (Control-IN and BULK-IN).
-+ *
-+ * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
-+ * are 8 EP Numbers in each of the other possible DTKNQ Registers.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ *
-+ */
-+static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_device_global_regs_t *dev_global_regs =
-+ core_if->dev_if->dev_global_regs;
-+ const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
-+ /* Number of Token Queue Registers */
-+ const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
-+ dtknq1_data_t dtknqr1;
-+ uint32_t in_tkn_epnums[4];
-+ int ndx = 0;
-+ int i = 0;
-+ volatile uint32_t *addr = &dev_global_regs->dtknqr1;
-+ int epnum = 0;
-+
-+ //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
-+
-+ /* Read the DTKNQ Registers */
-+ for (i = 0; i < DTKNQ_REG_CNT; i++) {
-+ in_tkn_epnums[i] = DWC_READ_REG32(addr);
-+ DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
-+ in_tkn_epnums[i]);
-+ if (addr == &dev_global_regs->dvbusdis) {
-+ addr = &dev_global_regs->dtknqr3_dthrctl;
-+ } else {
-+ ++addr;
-+ }
-+
-+ }
-+
-+ /* Copy the DTKNQR1 data to the bit field. */
-+ dtknqr1.d32 = in_tkn_epnums[0];
-+ /* Get the EP numbers */
-+ in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
-+ ndx = dtknqr1.b.intknwptr - 1;
-+
-+ //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
-+ if (ndx == -1) {
-+ /** @todo Find a simpler way to calculate the max
-+ * queue position.*/
-+ int cnt = TOKEN_Q_DEPTH;
-+ if (TOKEN_Q_DEPTH <= 6) {
-+ cnt = TOKEN_Q_DEPTH - 1;
-+ } else if (TOKEN_Q_DEPTH <= 14) {
-+ cnt = TOKEN_Q_DEPTH - 7;
-+ } else if (TOKEN_Q_DEPTH <= 22) {
-+ cnt = TOKEN_Q_DEPTH - 15;
-+ } else {
-+ cnt = TOKEN_Q_DEPTH - 23;
-+ }
-+ epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
-+ } else {
-+ if (ndx <= 5) {
-+ epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
-+ } else if (ndx <= 13) {
-+ ndx -= 6;
-+ epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
-+ } else if (ndx <= 21) {
-+ ndx -= 14;
-+ epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
-+ } else if (ndx <= 29) {
-+ ndx -= 22;
-+ epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
-+ }
-+ }
-+ //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
-+ return epnum;
-+}
-+
-+/**
-+ * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
-+ * The active request is checked for the next packet to be loaded into
-+ * the non-periodic Tx FIFO.
-+ */
-+int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ dwc_otg_dev_in_ep_regs_t *ep_regs;
-+ gnptxsts_data_t txstatus = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+
-+ int epnum = 0;
-+ dwc_otg_pcd_ep_t *ep = 0;
-+ uint32_t len = 0;
-+ int dwords;
-+
-+ /* Get the epnum from the IN Token Learning Queue. */
-+ epnum = get_ep_of_last_in_token(core_if);
-+ ep = get_in_ep(pcd, epnum);
-+
-+ DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
-+
-+ ep_regs = core_if->dev_if->in_ep_regs[epnum];
-+
-+ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
-+ if (len > ep->dwc_ep.maxpacket) {
-+ len = ep->dwc_ep.maxpacket;
-+ }
-+ dwords = (len + 3) / 4;
-+
-+ /* While there is space in the queue and space in the FIFO and
-+ * More data to tranfer, Write packets to the Tx FIFO */
-+ txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
-+ DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
-+
-+ while (txstatus.b.nptxqspcavail > 0 &&
-+ txstatus.b.nptxfspcavail > dwords &&
-+ ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
-+ /* Write the FIFO */
-+ dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
-+ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
-+
-+ if (len > ep->dwc_ep.maxpacket) {
-+ len = ep->dwc_ep.maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+ txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
-+ DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
-+ DWC_READ_REG32(&global_regs->gnptxsts));
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.nptxfempty = 1;
-+ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This function is called when dedicated Tx FIFO Empty interrupt occurs.
-+ * The active request is checked for the next packet to be loaded into
-+ * apropriate Tx FIFO.
-+ */
-+static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ dwc_otg_dev_in_ep_regs_t *ep_regs;
-+ dtxfsts_data_t txstatus = {.d32 = 0 };
-+ dwc_otg_pcd_ep_t *ep = 0;
-+ uint32_t len = 0;
-+ int dwords;
-+
-+ ep = get_in_ep(pcd, epnum);
-+
-+ DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
-+
-+ ep_regs = core_if->dev_if->in_ep_regs[epnum];
-+
-+ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
-+
-+ if (len > ep->dwc_ep.maxpacket) {
-+ len = ep->dwc_ep.maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+
-+ /* While there is space in the queue and space in the FIFO and
-+ * More data to tranfer, Write packets to the Tx FIFO */
-+ txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
-+ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
-+
-+ while (txstatus.b.txfspcavail > dwords &&
-+ ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
-+ ep->dwc_ep.xfer_len != 0) {
-+ /* Write the FIFO */
-+ dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
-+
-+ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
-+ if (len > ep->dwc_ep.maxpacket) {
-+ len = ep->dwc_ep.maxpacket;
-+ }
-+
-+ dwords = (len + 3) / 4;
-+ txstatus.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
-+ DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
-+ txstatus.d32);
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
-+ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
-+
-+ return 1;
-+}
-+
-+/**
-+ * This function is called when the Device is disconnected. It stops
-+ * any active requests and informs the Gadget driver of the
-+ * disconnect.
-+ */
-+void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
-+{
-+ int i, num_in_eps, num_out_eps;
-+ dwc_otg_pcd_ep_t *ep;
-+
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_SPINLOCK(pcd->lock);
-+
-+ num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
-+ num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
-+ /* don't disconnect drivers more than once */
-+ if (pcd->ep0state == EP0_DISCONNECT) {
-+ DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
-+ DWC_SPINUNLOCK(pcd->lock);
-+ return;
-+ }
-+ pcd->ep0state = EP0_DISCONNECT;
-+
-+ /* Reset the OTG state. */
-+ dwc_otg_pcd_update_otg(pcd, 1);
-+
-+ /* Disable the NP Tx Fifo Empty Interrupt. */
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+
-+ /* Flush the FIFOs */
-+ /**@todo NGS Flush Periodic FIFOs */
-+ dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
-+ dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
-+
-+ /* prevent new request submissions, kill any outstanding requests */
-+ ep = &pcd->ep0;
-+ dwc_otg_request_nuke(ep);
-+ /* prevent new request submissions, kill any outstanding requests */
-+ for (i = 0; i < num_in_eps; i++) {
-+ dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
-+ dwc_otg_request_nuke(ep);
-+ }
-+ /* prevent new request submissions, kill any outstanding requests */
-+ for (i = 0; i < num_out_eps; i++) {
-+ dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
-+ dwc_otg_request_nuke(ep);
-+ }
-+
-+ /* report disconnect; the driver is already quiesced */
-+ if (pcd->fops->disconnect) {
-+ DWC_SPINUNLOCK(pcd->lock);
-+ pcd->fops->disconnect(pcd);
-+ DWC_SPINLOCK(pcd->lock);
-+ }
-+ DWC_SPINUNLOCK(pcd->lock);
-+}
-+
-+/**
-+ * This interrupt indicates that ...
-+ */
-+int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+
-+ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
-+ intr_mask.b.i2cintr = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.i2cintr = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that ...
-+ */
-+int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintsts_data_t gintsts;
-+#if defined(VERBOSE)
-+ DWC_PRINTF("Early Suspend Detected\n");
-+#endif
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.erlysuspend = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+ return 1;
-+}
-+
-+/**
-+ * This function configures EPO to receive SETUP packets.
-+ *
-+ * @todo NGS: Update the comments from the HW FS.
-+ *
-+ * -# Program the following fields in the endpoint specific registers
-+ * for Control OUT EP 0, in order to receive a setup packet
-+ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
-+ * setup packets)
-+ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
-+ * to back setup packets)
-+ * - In DMA mode, DOEPDMA0 Register with a memory address to
-+ * store any setup packets received
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param pcd Programming view of the PCD.
-+ */
-+static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
-+ dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ deptsiz0_data_t doeptsize0 = {.d32 = 0 };
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ depctl_data_t doepctl = {.d32 = 0 };
-+
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
-+ DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
-+#endif
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
-+ if (doepctl.b.epena) {
-+ return;
-+ }
-+ }
-+
-+ doeptsize0.b.supcnt = 3;
-+ doeptsize0.b.pktcnt = 1;
-+ doeptsize0.b.xfersize = 8 * 3;
-+
-+ if (core_if->dma_enable) {
-+ if (!core_if->dma_desc_enable) {
-+ /** put here as for Hermes mode deptisz register should not be written */
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
-+ doeptsize0.d32);
-+
-+ /** @todo dma needs to handle multiple setup packets (up to 3) */
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
-+ pcd->setup_pkt_dma_handle);
-+ } else {
-+ dev_if->setup_desc_index =
-+ (dev_if->setup_desc_index + 1) & 1;
-+ dma_desc =
-+ dev_if->setup_desc_addr[dev_if->setup_desc_index];
-+
-+ /** DMA Descriptor Setup */
-+ dma_desc->status.b.bs = BS_HOST_BUSY;
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ dma_desc->status.b.sr = 0;
-+ dma_desc->status.b.mtrf = 0;
-+ }
-+ dma_desc->status.b.l = 1;
-+ dma_desc->status.b.ioc = 1;
-+ dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
-+ dma_desc->buf = pcd->setup_pkt_dma_handle;
-+ dma_desc->status.b.sts = 0;
-+ dma_desc->status.b.bs = BS_HOST_READY;
-+
-+ /** DOEPDMA0 Register write */
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma,
-+ dev_if->dma_setup_desc_addr
-+ [dev_if->setup_desc_index]);
-+ }
-+
-+ } else {
-+ /** put here as for Hermes mode deptisz register should not be written */
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz,
-+ doeptsize0.d32);
-+ }
-+
-+ /** DOEPCTL0 Register write cnak will be set after setup interrupt */
-+ doepctl.d32 = 0;
-+ doepctl.b.epena = 1;
-+ if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
-+ doepctl.b.cnak = 1;
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
-+ } else {
-+ DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32);
-+ }
-+
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
-+ DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
-+ DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
-+ DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
-+#endif
-+}
-+
-+/**
-+ * This interrupt occurs when a USB Reset is detected. When the USB
-+ * Reset Interrupt occurs the device state is set to DEFAULT and the
-+ * EP0 state is set to IDLE.
-+ * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
-+ * -# Unmask the following interrupt bits
-+ * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
-+ * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
-+ * - DOEPMSK.SETUP = 1
-+ * - DOEPMSK.XferCompl = 1
-+ * - DIEPMSK.XferCompl = 1
-+ * - DIEPMSK.TimeOut = 1
-+ * -# Program the following fields in the endpoint specific registers
-+ * for Control OUT EP 0, in order to receive a setup packet
-+ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
-+ * setup packets)
-+ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
-+ * to back setup packets)
-+ * - In DMA mode, DOEPDMA0 Register with a memory address to
-+ * store any setup packets received
-+ * At this point, all the required initialization, except for enabling
-+ * the control 0 OUT endpoint is done, for receiving SETUP packets.
-+ */
-+int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ depctl_data_t doepctl = {.d32 = 0 };
-+ depctl_data_t diepctl = {.d32 = 0 };
-+ daint_data_t daintmsk = {.d32 = 0 };
-+ doepmsk_data_t doepmsk = {.d32 = 0 };
-+ diepmsk_data_t diepmsk = {.d32 = 0 };
-+ dcfg_data_t dcfg = {.d32 = 0 };
-+ grstctl_t resetctl = {.d32 = 0 };
-+ dctl_data_t dctl = {.d32 = 0 };
-+ int i = 0;
-+ gintsts_data_t gintsts;
-+ pcgcctl_data_t power = {.d32 = 0 };
-+
-+ power.d32 = DWC_READ_REG32(core_if->pcgcctl);
-+ if (power.b.stoppclk) {
-+ power.d32 = 0;
-+ power.b.stoppclk = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
-+
-+ power.b.pwrclmp = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
-+
-+ power.b.rstpdwnmodule = 1;
-+ DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0);
-+ }
-+
-+ core_if->lx_state = DWC_OTG_L0;
-+
-+ DWC_PRINTF("USB RESET\n");
-+#ifdef DWC_EN_ISOC
-+ for (i = 1; i < 16; ++i) {
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+ ep = get_in_ep(pcd, i);
-+ if (ep != 0) {
-+ dwc_ep = &ep->dwc_ep;
-+ dwc_ep->next_frame = 0xffffffff;
-+ }
-+ }
-+#endif /* DWC_EN_ISOC */
-+
-+ /* reset the HNP settings */
-+ dwc_otg_pcd_update_otg(pcd, 1);
-+
-+ /* Clear the Remote Wakeup Signalling */
-+ dctl.b.rmtwkupsig = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
-+
-+ /* Set NAK for all OUT EPs */
-+ doepctl.b.snak = 1;
-+ for (i = 0; i <= dev_if->num_out_eps; i++) {
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
-+ }
-+
-+ /* Flush the NP Tx FIFO */
-+ dwc_otg_flush_tx_fifo(core_if, 0x10);
-+ /* Flush the Learning Queue */
-+ resetctl.b.intknqflsh = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
-+
-+ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
-+ core_if->start_predict = 0;
-+ for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
-+ core_if->nextep_seq[i] = 0xff; // 0xff - EP not active
-+ }
-+ core_if->nextep_seq[0] = 0;
-+ core_if->first_in_nextep_seq = 0;
-+ diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
-+ diepctl.b.nextep = 0;
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
-+
-+ /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
-+ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
-+ dcfg.b.epmscnt = 2;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
-+ __func__, core_if->first_in_nextep_seq);
-+ for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
-+ }
-+ }
-+
-+ if (core_if->multiproc_int_enable) {
-+ daintmsk.b.inep0 = 1;
-+ daintmsk.b.outep0 = 1;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk,
-+ daintmsk.d32);
-+
-+ doepmsk.b.setup = 1;
-+ doepmsk.b.xfercompl = 1;
-+ doepmsk.b.ahberr = 1;
-+ doepmsk.b.epdisabled = 1;
-+
-+ if ((core_if->dma_desc_enable) ||
-+ (core_if->dma_enable
-+ && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
-+ doepmsk.b.stsphsercvd = 1;
-+ }
-+ if (core_if->dma_desc_enable)
-+ doepmsk.b.bna = 1;
-+/*
-+ doepmsk.b.babble = 1;
-+ doepmsk.b.nyet = 1;
-+
-+ if (core_if->dma_enable) {
-+ doepmsk.b.nak = 1;
-+ }
-+*/
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0],
-+ doepmsk.d32);
-+
-+ diepmsk.b.xfercompl = 1;
-+ diepmsk.b.timeout = 1;
-+ diepmsk.b.epdisabled = 1;
-+ diepmsk.b.ahberr = 1;
-+ diepmsk.b.intknepmis = 1;
-+ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
-+ diepmsk.b.intknepmis = 0;
-+
-+/* if (core_if->dma_desc_enable) {
-+ diepmsk.b.bna = 1;
-+ }
-+*/
-+/*
-+ if (core_if->dma_enable) {
-+ diepmsk.b.nak = 1;
-+ }
-+*/
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0],
-+ diepmsk.d32);
-+ } else {
-+ daintmsk.b.inep0 = 1;
-+ daintmsk.b.outep0 = 1;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk,
-+ daintmsk.d32);
-+
-+ doepmsk.b.setup = 1;
-+ doepmsk.b.xfercompl = 1;
-+ doepmsk.b.ahberr = 1;
-+ doepmsk.b.epdisabled = 1;
-+
-+ if ((core_if->dma_desc_enable) ||
-+ (core_if->dma_enable
-+ && core_if->snpsid >= OTG_CORE_REV_3_00a)) {
-+ doepmsk.b.stsphsercvd = 1;
-+ }
-+ if (core_if->dma_desc_enable)
-+ doepmsk.b.bna = 1;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
-+
-+ diepmsk.b.xfercompl = 1;
-+ diepmsk.b.timeout = 1;
-+ diepmsk.b.epdisabled = 1;
-+ diepmsk.b.ahberr = 1;
-+ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
-+ diepmsk.b.intknepmis = 0;
-+/*
-+ if (core_if->dma_desc_enable) {
-+ diepmsk.b.bna = 1;
-+ }
-+*/
-+
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
-+ }
-+
-+ /* Reset Device Address */
-+ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
-+ dcfg.b.devaddr = 0;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
-+
-+ /* setup EP0 to receive SETUP packets */
-+ if (core_if->snpsid <= OTG_CORE_REV_2_94a)
-+ ep0_out_start(core_if, pcd);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.usbreset = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Get the device speed from the device status register and convert it
-+ * to USB speed constant.
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ */
-+static int get_device_speed(dwc_otg_core_if_t * core_if)
-+{
-+ dsts_data_t dsts;
-+ int speed = 0;
-+ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
-+
-+ switch (dsts.b.enumspd) {
-+ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
-+ speed = USB_SPEED_HIGH;
-+ break;
-+ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
-+ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
-+ speed = USB_SPEED_FULL;
-+ break;
-+
-+ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
-+ speed = USB_SPEED_LOW;
-+ break;
-+ }
-+
-+ return speed;
-+}
-+
-+/**
-+ * Read the device status register and set the device speed in the
-+ * data structure.
-+ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
-+ */
-+int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+ gintsts_data_t gintsts;
-+ gusbcfg_data_t gusbcfg;
-+ dwc_otg_core_global_regs_t *global_regs =
-+ GET_CORE_IF(pcd)->core_global_regs;
-+ uint8_t utmi16b, utmi8b;
-+ int speed;
-+ DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
-+
-+ if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
-+ utmi16b = 6; //vahrama old value was 6;
-+ utmi8b = 9;
-+ } else {
-+ utmi16b = 4;
-+ utmi8b = 8;
-+ }
-+ dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
-+ if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) {
-+ ep0_out_start(GET_CORE_IF(pcd), pcd);
-+ }
-+
-+#ifdef DEBUG_EP0
-+ print_ep0_state(pcd);
-+#endif
-+
-+ if (pcd->ep0state == EP0_DISCONNECT) {
-+ pcd->ep0state = EP0_IDLE;
-+ } else if (pcd->ep0state == EP0_STALL) {
-+ pcd->ep0state = EP0_IDLE;
-+ }
-+
-+ pcd->ep0state = EP0_IDLE;
-+
-+ ep0->stopped = 0;
-+
-+ speed = get_device_speed(GET_CORE_IF(pcd));
-+ pcd->fops->connect(pcd, speed);
-+
-+ /* Set USB turnaround time based on device speed and PHY interface. */
-+ gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
-+ if (speed == USB_SPEED_HIGH) {
-+ if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
-+ DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
-+ /* ULPI interface */
-+ gusbcfg.b.usbtrdtim = 9;
-+ }
-+ if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
-+ DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
-+ /* UTMI+ interface */
-+ if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
-+ gusbcfg.b.usbtrdtim = utmi8b;
-+ } else if (GET_CORE_IF(pcd)->hwcfg4.
-+ b.utmi_phy_data_width == 1) {
-+ gusbcfg.b.usbtrdtim = utmi16b;
-+ } else if (GET_CORE_IF(pcd)->
-+ core_params->phy_utmi_width == 8) {
-+ gusbcfg.b.usbtrdtim = utmi8b;
-+ } else {
-+ gusbcfg.b.usbtrdtim = utmi16b;
-+ }
-+ }
-+ if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
-+ DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
-+ /* UTMI+ OR ULPI interface */
-+ if (gusbcfg.b.ulpi_utmi_sel == 1) {
-+ /* ULPI interface */
-+ gusbcfg.b.usbtrdtim = 9;
-+ } else {
-+ /* UTMI+ interface */
-+ if (GET_CORE_IF(pcd)->
-+ core_params->phy_utmi_width == 16) {
-+ gusbcfg.b.usbtrdtim = utmi16b;
-+ } else {
-+ gusbcfg.b.usbtrdtim = utmi8b;
-+ }
-+ }
-+ }
-+ } else {
-+ /* Full or low speed */
-+ gusbcfg.b.usbtrdtim = 9;
-+ }
-+ DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.enumdone = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that the ISO OUT Packet was dropped due to
-+ * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
-+ * read all the data from the Rx FIFO.
-+ */
-+int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+
-+ DWC_WARN("INTERRUPT Handler not implemented for %s\n",
-+ "ISOC Out Dropped");
-+
-+ intr_mask.b.isooutdrop = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.isooutdrop = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates the end of the portion of the micro-frame
-+ * for periodic transactions. If there is a periodic transaction for
-+ * the next frame, load the packets into the EP periodic Tx FIFO.
-+ */
-+int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
-+
-+ intr_mask.b.eopframe = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.eopframe = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that EP of the packet on the top of the
-+ * non-periodic Tx FIFO does not match EP of the IN Token received.
-+ *
-+ * The "Device IN Token Queue" Registers are read to determine the
-+ * order the IN Tokens have been received. The non-periodic Tx FIFO
-+ * is flushed, so it can be reloaded in the order seen in the IN Token
-+ * Queue.
-+ */
-+int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintsts_data_t gintsts;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dctl_data_t dctl;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) {
-+ core_if->start_predict = 1;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
-+
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ if (!gintsts.b.ginnakeff) {
-+ /* Disable EP Mismatch interrupt */
-+ intr_mask.d32 = 0;
-+ intr_mask.b.epmismatch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
-+ /* Enable the Global IN NAK Effective Interrupt */
-+ intr_mask.d32 = 0;
-+ intr_mask.b.ginnakeff = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
-+ /* Set the global non-periodic IN NAK handshake */
-+ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
-+ dctl.b.sgnpinnak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
-+ } else {
-+ DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n");
-+ }
-+ /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective()
-+ * handler after Global IN NAK Effective interrupt will be asserted */
-+ }
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.epmismatch = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt is valid only in DMA mode. This interrupt indicates that the
-+ * core has stopped fetching data for IN endpoints due to the unavailability of
-+ * TxFIFO space or Request Queue space. This interrupt is used by the
-+ * application for an endpoint mismatch algorithm.
-+ *
-+ * @param pcd The PCD
-+ */
-+int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintsts_data_t gintsts;
-+ gintmsk_data_t gintmsk_data;
-+ dctl_data_t dctl;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
-+
-+ /* Clear the global non-periodic IN NAK handshake */
-+ dctl.d32 = 0;
-+ dctl.b.cgnpinnak = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
-+
-+ /* Mask GINTSTS.FETSUSP interrupt */
-+ gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+ gintmsk_data.b.fetsusp = 0;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.fetsusp = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
-+
-+ return 1;
-+}
-+/**
-+ * This funcion stalls EP0.
-+ */
-+static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
-+{
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+ usb_device_request_t *ctrl = &pcd->setup_pkt->req;
-+ DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
-+ ctrl->bmRequestType, ctrl->bRequest, err_val);
-+
-+ ep0->dwc_ep.is_in = 1;
-+ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
-+ pcd->ep0.stopped = 1;
-+ pcd->ep0state = EP0_IDLE;
-+ ep0_out_start(GET_CORE_IF(pcd), pcd);
-+}
-+
-+/**
-+ * This functions delegates the setup command to the gadget driver.
-+ */
-+static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
-+ usb_device_request_t * ctrl)
-+{
-+ int ret = 0;
-+ DWC_SPINUNLOCK(pcd->lock);
-+ ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
-+ DWC_SPINLOCK(pcd->lock);
-+ if (ret < 0) {
-+ ep0_do_stall(pcd, ret);
-+ }
-+
-+ /** @todo This is a g_file_storage gadget driver specific
-+ * workaround: a DELAYED_STATUS result from the fsg_setup
-+ * routine will result in the gadget queueing a EP0 IN status
-+ * phase for a two-stage control transfer. Exactly the same as
-+ * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
-+ * specific request. Need a generic way to know when the gadget
-+ * driver will queue the status phase. Can we assume when we
-+ * call the gadget driver setup() function that it will always
-+ * queue and require the following flag? Need to look into
-+ * this.
-+ */
-+
-+ if (ret == 256 + 999) {
-+ pcd->request_config = 1;
-+ }
-+}
-+
-+#ifdef DWC_UTE_CFI
-+/**
-+ * This functions delegates the CFI setup commands to the gadget driver.
-+ * This function will return a negative value to indicate a failure.
-+ */
-+static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
-+ struct cfi_usb_ctrlrequest *ctrl_req)
-+{
-+ int ret = 0;
-+
-+ if (pcd->fops && pcd->fops->cfi_setup) {
-+ DWC_SPINUNLOCK(pcd->lock);
-+ ret = pcd->fops->cfi_setup(pcd, ctrl_req);
-+ DWC_SPINLOCK(pcd->lock);
-+ if (ret < 0) {
-+ ep0_do_stall(pcd, ret);
-+ return ret;
-+ }
-+ }
-+
-+ return ret;
-+}
-+#endif
-+
-+/**
-+ * This function starts the Zero-Length Packet for the IN status phase
-+ * of a 2 stage control transfer.
-+ */
-+static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+ if (pcd->ep0state == EP0_STALL) {
-+ return;
-+ }
-+
-+ pcd->ep0state = EP0_IN_STATUS_PHASE;
-+
-+ /* Prepare for more SETUP Packets */
-+ DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
-+ if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a)
-+ && (pcd->core_if->dma_desc_enable)
-+ && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) {
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "Data terminated wait next packet in out_desc_addr\n");
-+ pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr);
-+ pcd->data_terminated = 1;
-+ }
-+ ep0->dwc_ep.xfer_len = 0;
-+ ep0->dwc_ep.xfer_count = 0;
-+ ep0->dwc_ep.is_in = 1;
-+ ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
-+ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
-+
-+ /* Prepare for more SETUP Packets */
-+ //ep0_out_start(GET_CORE_IF(pcd), pcd);
-+}
-+
-+/**
-+ * This function starts the Zero-Length Packet for the OUT status phase
-+ * of a 2 stage control transfer.
-+ */
-+static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+ if (pcd->ep0state == EP0_STALL) {
-+ DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
-+ return;
-+ }
-+ pcd->ep0state = EP0_OUT_STATUS_PHASE;
-+
-+ DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
-+ ep0->dwc_ep.xfer_len = 0;
-+ ep0->dwc_ep.xfer_count = 0;
-+ ep0->dwc_ep.is_in = 0;
-+ ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
-+ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
-+
-+ /* Prepare for more SETUP Packets */
-+ if (GET_CORE_IF(pcd)->dma_enable == 0) {
-+ ep0_out_start(GET_CORE_IF(pcd), pcd);
-+ }
-+}
-+
-+/**
-+ * Clear the EP halt (STALL) and if pending requests start the
-+ * transfer.
-+ */
-+static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
-+{
-+ if (ep->dwc_ep.stall_clear_flag == 0)
-+ dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
-+
-+ /* Reactive the EP */
-+ dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
-+ if (ep->stopped) {
-+ ep->stopped = 0;
-+ /* If there is a request in the EP queue start it */
-+
-+ /** @todo FIXME: this causes an EP mismatch in DMA mode.
-+ * epmismatch not yet implemented. */
-+
-+ /*
-+ * Above fixme is solved by implmenting a tasklet to call the
-+ * start_next_request(), outside of interrupt context at some
-+ * time after the current time, after a clear-halt setup packet.
-+ * Still need to implement ep mismatch in the future if a gadget
-+ * ever uses more than one endpoint at once
-+ */
-+ ep->queue_sof = 1;
-+ DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
-+ }
-+ /* Start Control Status Phase */
-+ do_setup_in_status_phase(pcd);
-+}
-+
-+/**
-+ * This function is called when the SET_FEATURE TEST_MODE Setup packet
-+ * is sent from the host. The Device Control register is written with
-+ * the Test Mode bits set to the specified Test Mode. This is done as
-+ * a tasklet so that the "Status" phase of the control transfer
-+ * completes before transmitting the TEST packets.
-+ *
-+ * @todo This has not been tested since the tasklet struct was put
-+ * into the PCD struct!
-+ *
-+ */
-+void do_test_mode(void *data)
-+{
-+ dctl_data_t dctl;
-+ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ int test_mode = pcd->test_mode;
-+
-+// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
-+
-+ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
-+ switch (test_mode) {
-+ case 1: // TEST_J
-+ dctl.b.tstctl = 1;
-+ break;
-+
-+ case 2: // TEST_K
-+ dctl.b.tstctl = 2;
-+ break;
-+
-+ case 3: // TEST_SE0_NAK
-+ dctl.b.tstctl = 3;
-+ break;
-+
-+ case 4: // TEST_PACKET
-+ dctl.b.tstctl = 4;
-+ break;
-+
-+ case 5: // TEST_FORCE_ENABLE
-+ dctl.b.tstctl = 5;
-+ break;
-+ }
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
-+}
-+
-+/**
-+ * This function process the GET_STATUS Setup Commands.
-+ */
-+static inline void do_get_status(dwc_otg_pcd_t * pcd)
-+{
-+ usb_device_request_t ctrl = pcd->setup_pkt->req;
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+ uint16_t *status = pcd->status_buf;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD,
-+ "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
-+ ctrl.bmRequestType, ctrl.bRequest,
-+ UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
-+ UGETW(ctrl.wLength));
-+#endif
-+
-+ switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
-+ case UT_DEVICE:
-+ if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */
-+ DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex));
-+ DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver);
-+ DWC_PRINTF("OTG CAP - %d, %d\n",
-+ core_if->core_params->otg_cap,
-+ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
-+ if (core_if->otg_ver == 1
-+ && core_if->core_params->otg_cap ==
-+ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
-+ uint8_t *otgsts = (uint8_t*)pcd->status_buf;
-+ *otgsts = (core_if->otg_sts & 0x1);
-+ pcd->ep0_pending = 1;
-+ ep0->dwc_ep.start_xfer_buff =
-+ (uint8_t *) otgsts;
-+ ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts;
-+ ep0->dwc_ep.dma_addr =
-+ pcd->status_buf_dma_handle;
-+ ep0->dwc_ep.xfer_len = 1;
-+ ep0->dwc_ep.xfer_count = 0;
-+ ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
-+ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
-+ &ep0->dwc_ep);
-+ return;
-+ } else {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ break;
-+ } else {
-+ *status = 0x1; /* Self powered */
-+ *status |= pcd->remote_wakeup_enable << 1;
-+ break;
-+ }
-+ case UT_INTERFACE:
-+ *status = 0;
-+ break;
-+
-+ case UT_ENDPOINT:
-+ ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
-+ if (ep == 0 || UGETW(ctrl.wLength) > 2) {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ /** @todo check for EP stall */
-+ *status = ep->stopped;
-+ break;
-+ }
-+ pcd->ep0_pending = 1;
-+ ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
-+ ep0->dwc_ep.xfer_buff = (uint8_t *) status;
-+ ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
-+ ep0->dwc_ep.xfer_len = 2;
-+ ep0->dwc_ep.xfer_count = 0;
-+ ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
-+ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
-+}
-+
-+/**
-+ * This function process the SET_FEATURE Setup Commands.
-+ */
-+static inline void do_set_feature(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+ usb_device_request_t ctrl = pcd->setup_pkt->req;
-+ dwc_otg_pcd_ep_t *ep = 0;
-+ int32_t otg_cap_param = core_if->core_params->otg_cap;
-+ gotgctl_data_t gotgctl = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
-+ ctrl.bmRequestType, ctrl.bRequest,
-+ UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
-+ UGETW(ctrl.wLength));
-+ DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
-+
-+ switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
-+ case UT_DEVICE:
-+ switch (UGETW(ctrl.wValue)) {
-+ case UF_DEVICE_REMOTE_WAKEUP:
-+ pcd->remote_wakeup_enable = 1;
-+ break;
-+
-+ case UF_TEST_MODE:
-+ /* Setup the Test Mode tasklet to do the Test
-+ * Packet generation after the SETUP Status
-+ * phase has completed. */
-+
-+ /** @todo This has not been tested since the
-+ * tasklet struct was put into the PCD
-+ * struct! */
-+ pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
-+ DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
-+ break;
-+
-+ case UF_DEVICE_B_HNP_ENABLE:
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
-+
-+ /* dev may initiate HNP */
-+ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
-+ pcd->b_hnp_enable = 1;
-+ dwc_otg_pcd_update_otg(pcd, 0);
-+ DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
-+ /**@todo Is the gotgctl.devhnpen cleared
-+ * by a USB Reset? */
-+ gotgctl.b.devhnpen = 1;
-+ gotgctl.b.hnpreq = 1;
-+ DWC_WRITE_REG32(&global_regs->gotgctl,
-+ gotgctl.d32);
-+ } else {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ break;
-+
-+ case UF_DEVICE_A_HNP_SUPPORT:
-+ /* RH port supports HNP */
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
-+ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
-+ pcd->a_hnp_support = 1;
-+ dwc_otg_pcd_update_otg(pcd, 0);
-+ } else {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ break;
-+
-+ case UF_DEVICE_A_ALT_HNP_SUPPORT:
-+ /* other RH port does */
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
-+ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
-+ pcd->a_alt_hnp_support = 1;
-+ dwc_otg_pcd_update_otg(pcd, 0);
-+ } else {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ break;
-+
-+ default:
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+
-+ }
-+ do_setup_in_status_phase(pcd);
-+ break;
-+
-+ case UT_INTERFACE:
-+ do_gadget_setup(pcd, &ctrl);
-+ break;
-+
-+ case UT_ENDPOINT:
-+ if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
-+ ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
-+ if (ep == 0) {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ ep->stopped = 1;
-+ dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
-+ }
-+ do_setup_in_status_phase(pcd);
-+ break;
-+ }
-+}
-+
-+/**
-+ * This function process the CLEAR_FEATURE Setup Commands.
-+ */
-+static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
-+{
-+ usb_device_request_t ctrl = pcd->setup_pkt->req;
-+ dwc_otg_pcd_ep_t *ep = 0;
-+
-+ DWC_DEBUGPL(DBG_PCD,
-+ "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
-+ ctrl.bmRequestType, ctrl.bRequest,
-+ UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
-+ UGETW(ctrl.wLength));
-+
-+ switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
-+ case UT_DEVICE:
-+ switch (UGETW(ctrl.wValue)) {
-+ case UF_DEVICE_REMOTE_WAKEUP:
-+ pcd->remote_wakeup_enable = 0;
-+ break;
-+
-+ case UF_TEST_MODE:
-+ /** @todo Add CLEAR_FEATURE for TEST modes. */
-+ break;
-+
-+ default:
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+ do_setup_in_status_phase(pcd);
-+ break;
-+
-+ case UT_ENDPOINT:
-+ ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
-+ if (ep == 0) {
-+ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
-+ return;
-+ }
-+
-+ pcd_clear_halt(pcd, ep);
-+
-+ break;
-+ }
-+}
-+
-+/**
-+ * This function process the SET_ADDRESS Setup Commands.
-+ */
-+static inline void do_set_address(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
-+ usb_device_request_t ctrl = pcd->setup_pkt->req;
-+
-+ if (ctrl.bmRequestType == UT_DEVICE) {
-+ dcfg_data_t dcfg = {.d32 = 0 };
-+
-+#ifdef DEBUG_EP0
-+// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
-+#endif
-+ dcfg.b.devaddr = UGETW(ctrl.wValue);
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
-+ do_setup_in_status_phase(pcd);
-+ }
-+}
-+
-+/**
-+ * This function processes SETUP commands. In Linux, the USB Command
-+ * processing is done in two places - the first being the PCD and the
-+ * second in the Gadget Driver (for example, the File-Backed Storage
-+ * Gadget Driver).
-+ *
-+ * <table>
-+ * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
-+ *
-+ * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
-+ * defined in chapter 9 of the USB 2.0 Specification chapter 9
-+ * </td></tr>
-+ *
-+ * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
-+ * requests are the ENDPOINT_HALT feature is procesed, all others the
-+ * interface requests are ignored.</td></tr>
-+ *
-+ * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
-+ * requests are processed by the PCD. Interface requests are passed
-+ * to the Gadget Driver.</td></tr>
-+ *
-+ * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
-+ * with device address received </td></tr>
-+ *
-+ * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
-+ * requested descriptor</td></tr>
-+ *
-+ * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
-+ * not implemented by any of the existing Gadget Drivers.</td></tr>
-+ *
-+ * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
-+ * all EPs and enable EPs for new configuration.</td></tr>
-+ *
-+ * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
-+ * the current configuration</td></tr>
-+ *
-+ * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
-+ * EPs and enable EPs for new configuration.</td></tr>
-+ *
-+ * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
-+ * current interface.</td></tr>
-+ *
-+ * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
-+ * message.</td></tr>
-+ * </table>
-+ *
-+ * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
-+ * processed by pcd_setup. Calling the Function Driver's setup function from
-+ * pcd_setup processes the gadget SETUP commands.
-+ */
-+static inline void pcd_setup(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ usb_device_request_t ctrl = pcd->setup_pkt->req;
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+
-+ deptsiz0_data_t doeptsize0 = {.d32 = 0 };
-+
-+#ifdef DWC_UTE_CFI
-+ int retval = 0;
-+ struct cfi_usb_ctrlrequest cfi_req;
-+#endif
-+
-+ doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz);
-+
-+ /** In BDMA more then 1 setup packet is not supported till 3.00a */
-+ if (core_if->dma_enable && core_if->dma_desc_enable == 0
-+ && (doeptsize0.b.supcnt < 2)
-+ && (core_if->snpsid < OTG_CORE_REV_2_94a)) {
-+ DWC_ERROR
-+ ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
-+ }
-+ if ((core_if->snpsid >= OTG_CORE_REV_3_00a)
-+ && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) {
-+ ctrl =
-+ (pcd->setup_pkt +
-+ (3 - doeptsize0.b.supcnt - 1 +
-+ ep0->dwc_ep.stp_rollover))->req;
-+ }
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
-+ ctrl.bmRequestType, ctrl.bRequest,
-+ UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
-+ UGETW(ctrl.wLength));
-+#endif
-+
-+ /* Clean up the request queue */
-+ dwc_otg_request_nuke(ep0);
-+ ep0->stopped = 0;
-+
-+ if (ctrl.bmRequestType & UE_DIR_IN) {
-+ ep0->dwc_ep.is_in = 1;
-+ pcd->ep0state = EP0_IN_DATA_PHASE;
-+ } else {
-+ ep0->dwc_ep.is_in = 0;
-+ pcd->ep0state = EP0_OUT_DATA_PHASE;
-+ }
-+
-+ if (UGETW(ctrl.wLength) == 0) {
-+ ep0->dwc_ep.is_in = 1;
-+ pcd->ep0state = EP0_IN_STATUS_PHASE;
-+ }
-+
-+ if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
-+
-+#ifdef DWC_UTE_CFI
-+ DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
-+
-+ //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n",
-+ ctrl.bRequestType, ctrl.bRequest);
-+ if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
-+ if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
-+ retval = cfi_setup(pcd, &cfi_req);
-+ if (retval < 0) {
-+ ep0_do_stall(pcd, retval);
-+ pcd->ep0_pending = 0;
-+ return;
-+ }
-+
-+ /* if need gadget setup then call it and check the retval */
-+ if (pcd->cfi->need_gadget_att) {
-+ retval =
-+ cfi_gadget_setup(pcd,
-+ &pcd->
-+ cfi->ctrl_req);
-+ if (retval < 0) {
-+ pcd->ep0_pending = 0;
-+ return;
-+ }
-+ }
-+
-+ if (pcd->cfi->need_status_in_complete) {
-+ do_setup_in_status_phase(pcd);
-+ }
-+ return;
-+ }
-+ }
-+#endif
-+
-+ /* handle non-standard (class/vendor) requests in the gadget driver */
-+ do_gadget_setup(pcd, &ctrl);
-+ return;
-+ }
-+
-+ /** @todo NGS: Handle bad setup packet? */
-+
-+///////////////////////////////////////////
-+//// --- Standard Request handling --- ////
-+
-+ switch (ctrl.bRequest) {
-+ case UR_GET_STATUS:
-+ do_get_status(pcd);
-+ break;
-+
-+ case UR_CLEAR_FEATURE:
-+ do_clear_feature(pcd);
-+ break;
-+
-+ case UR_SET_FEATURE:
-+ do_set_feature(pcd);
-+ break;
-+
-+ case UR_SET_ADDRESS:
-+ do_set_address(pcd);
-+ break;
-+
-+ case UR_SET_INTERFACE:
-+ case UR_SET_CONFIG:
-+// _pcd->request_config = 1; /* Configuration changed */
-+ do_gadget_setup(pcd, &ctrl);
-+ break;
-+
-+ case UR_SYNCH_FRAME:
-+ do_gadget_setup(pcd, &ctrl);
-+ break;
-+
-+ default:
-+ /* Call the Gadget Driver's setup functions */
-+ do_gadget_setup(pcd, &ctrl);
-+ break;
-+ }
-+}
-+
-+/**
-+ * This function completes the ep0 control transfer.
-+ */
-+static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ dwc_otg_dev_in_ep_regs_t *in_ep_regs =
-+ dev_if->in_ep_regs[ep->dwc_ep.num];
-+#ifdef DEBUG_EP0
-+ dwc_otg_dev_out_ep_regs_t *out_ep_regs =
-+ dev_if->out_ep_regs[ep->dwc_ep.num];
-+#endif
-+ deptsiz0_data_t deptsiz;
-+ dev_dma_desc_sts_t desc_sts;
-+ dwc_otg_pcd_request_t *req;
-+ int is_last = 0;
-+ dwc_otg_pcd_t *pcd = ep->pcd;
-+
-+#ifdef DWC_UTE_CFI
-+ struct cfi_usb_ctrlrequest *ctrlreq;
-+ int retval = -DWC_E_NOT_SUPPORTED;
-+#endif
-+
-+ desc_sts.b.bytes = 0;
-+
-+ if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ if (ep->dwc_ep.is_in) {
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
-+#endif
-+ do_setup_out_status_phase(pcd);
-+ } else {
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
-+#endif
-+
-+#ifdef DWC_UTE_CFI
-+ ctrlreq = &pcd->cfi->ctrl_req;
-+
-+ if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
-+ if (ctrlreq->bRequest > 0xB0
-+ && ctrlreq->bRequest < 0xBF) {
-+
-+ /* Return if the PCD failed to handle the request */
-+ if ((retval =
-+ pcd->cfi->ops.
-+ ctrl_write_complete(pcd->cfi,
-+ pcd)) < 0) {
-+ CFI_INFO
-+ ("ERROR setting a new value in the PCD(%d)\n",
-+ retval);
-+ ep0_do_stall(pcd, retval);
-+ pcd->ep0_pending = 0;
-+ return 0;
-+ }
-+
-+ /* If the gadget needs to be notified on the request */
-+ if (pcd->cfi->need_gadget_att == 1) {
-+ //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
-+ retval =
-+ cfi_gadget_setup(pcd,
-+ &pcd->cfi->
-+ ctrl_req);
-+
-+ /* Return from the function if the gadget failed to process
-+ * the request properly - this should never happen !!!
-+ */
-+ if (retval < 0) {
-+ CFI_INFO
-+ ("ERROR setting a new value in the gadget(%d)\n",
-+ retval);
-+ pcd->ep0_pending = 0;
-+ return 0;
-+ }
-+ }
-+
-+ CFI_INFO("%s: RETVAL=%d\n", __func__,
-+ retval);
-+ /* If we hit here then the PCD and the gadget has properly
-+ * handled the request - so send the ZLP IN to the host.
-+ */
-+ /* @todo: MAS - decide whether we need to start the setup
-+ * stage based on the need_setup value of the cfi object
-+ */
-+ do_setup_in_status_phase(pcd);
-+ pcd->ep0_pending = 0;
-+ return 1;
-+ }
-+ }
-+#endif
-+
-+ do_setup_in_status_phase(pcd);
-+ }
-+ pcd->ep0_pending = 0;
-+ return 1;
-+ }
-+
-+ if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ return 0;
-+ }
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+
-+ if (pcd->ep0state == EP0_OUT_STATUS_PHASE
-+ || pcd->ep0state == EP0_IN_STATUS_PHASE) {
-+ is_last = 1;
-+ } else if (ep->dwc_ep.is_in) {
-+ deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
-+ if (core_if->dma_desc_enable != 0)
-+ desc_sts = dev_if->in_desc_addr->status;
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n",
-+ ep->dwc_ep.num, ep->dwc_ep.xfer_len,
-+ deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+#endif
-+
-+ if (((core_if->dma_desc_enable == 0)
-+ && (deptsiz.b.xfersize == 0))
-+ || ((core_if->dma_desc_enable != 0)
-+ && (desc_sts.b.bytes == 0))) {
-+ req->actual = ep->dwc_ep.xfer_count;
-+ /* Is a Zero Len Packet needed? */
-+ if (req->sent_zlp) {
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
-+#endif
-+ req->sent_zlp = 0;
-+ }
-+ do_setup_out_status_phase(pcd);
-+ }
-+ } else {
-+ /* ep0-OUT */
-+#ifdef DEBUG_EP0
-+ deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz);
-+ DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
-+ ep->dwc_ep.num, ep->dwc_ep.xfer_len,
-+ deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+#endif
-+ req->actual = ep->dwc_ep.xfer_count;
-+
-+ /* Is a Zero Len Packet needed? */
-+ if (req->sent_zlp) {
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
-+#endif
-+ req->sent_zlp = 0;
-+ }
-+ /* For older cores do setup in status phase in Slave/BDMA modes,
-+ * starting from 3.00 do that only in slave, and for DMA modes
-+ * just re-enable ep 0 OUT here*/
-+ if (core_if->dma_enable == 0
-+ || (core_if->dma_desc_enable == 0
-+ && core_if->snpsid <= OTG_CORE_REV_2_94a)) {
-+ do_setup_in_status_phase(pcd);
-+ } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "Enable out ep before in status phase\n");
-+ ep0_out_start(core_if, pcd);
-+ }
-+ }
-+
-+ /* Complete the request */
-+ if (is_last) {
-+ dwc_otg_request_done(ep, req, 0);
-+ ep->dwc_ep.start_xfer_buff = 0;
-+ ep->dwc_ep.xfer_buff = 0;
-+ ep->dwc_ep.xfer_len = 0;
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+#ifdef DWC_UTE_CFI
-+/**
-+ * This function calculates traverses all the CFI DMA descriptors and
-+ * and accumulates the bytes that are left to be transfered.
-+ *
-+ * @return The total bytes left to transfered, or a negative value as failure
-+ */
-+static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
-+{
-+ int32_t ret = 0;
-+ int i;
-+ struct dwc_otg_dma_desc *ddesc = NULL;
-+ struct cfi_ep *cfiep;
-+
-+ /* See if the pcd_ep has its respective cfi_ep mapped */
-+ cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
-+ if (!cfiep) {
-+ CFI_INFO("%s: Failed to find ep\n", __func__);
-+ return -1;
-+ }
-+
-+ ddesc = ep->dwc_ep.descs;
-+
-+ for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
-+
-+#if defined(PRINT_CFI_DMA_DESCS)
-+ print_desc(ddesc, ep->ep.name, i);
-+#endif
-+ ret += ddesc->status.b.bytes;
-+ ddesc++;
-+ }
-+
-+ if (ret)
-+ CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
-+ ret);
-+
-+ return ret;
-+}
-+#endif
-+
-+/**
-+ * This function completes the request for the EP. If there are
-+ * additional requests for the EP in the queue they will be started.
-+ */
-+static void complete_ep(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ dwc_otg_dev_in_ep_regs_t *in_ep_regs =
-+ dev_if->in_ep_regs[ep->dwc_ep.num];
-+ deptsiz_data_t deptsiz;
-+ dev_dma_desc_sts_t desc_sts;
-+ dwc_otg_pcd_request_t *req = 0;
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ uint32_t byte_count = 0;
-+ int is_last = 0;
-+ int i;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
-+ (ep->dwc_ep.is_in ? "IN" : "OUT"));
-+
-+ /* Get any pending requests */
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ if (!req) {
-+ DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
-+ return;
-+ }
-+ } else {
-+ DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
-+ return;
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
-+
-+ if (ep->dwc_ep.is_in) {
-+ deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz);
-+
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable == 0) {
-+ if (deptsiz.b.xfersize == 0
-+ && deptsiz.b.pktcnt == 0) {
-+ byte_count =
-+ ep->dwc_ep.xfer_len -
-+ ep->dwc_ep.xfer_count;
-+
-+ ep->dwc_ep.xfer_buff += byte_count;
-+ ep->dwc_ep.dma_addr += byte_count;
-+ ep->dwc_ep.xfer_count += byte_count;
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "%d-%s len=%d xfersize=%d pktcnt=%d\n",
-+ ep->dwc_ep.num,
-+ (ep->dwc_ep.
-+ is_in ? "IN" : "OUT"),
-+ ep->dwc_ep.xfer_len,
-+ deptsiz.b.xfersize,
-+ deptsiz.b.pktcnt);
-+
-+ if (ep->dwc_ep.xfer_len <
-+ ep->dwc_ep.total_len) {
-+ dwc_otg_ep_start_transfer
-+ (core_if, &ep->dwc_ep);
-+ } else if (ep->dwc_ep.sent_zlp) {
-+ /*
-+ * This fragment of code should initiate 0
-+ * length transfer in case if it is queued
-+ * a transfer with size divisible to EPs max
-+ * packet size and with usb_request zero field
-+ * is set, which means that after data is transfered,
-+ * it is also should be transfered
-+ * a 0 length packet at the end. For Slave and
-+ * Buffer DMA modes in this case SW has
-+ * to initiate 2 transfers one with transfer size,
-+ * and the second with 0 size. For Descriptor
-+ * DMA mode SW is able to initiate a transfer,
-+ * which will handle all the packets including
-+ * the last 0 length.
-+ */
-+ ep->dwc_ep.sent_zlp = 0;
-+ dwc_otg_ep_start_zl_transfer
-+ (core_if, &ep->dwc_ep);
-+ } else {
-+ is_last = 1;
-+ }
-+ } else {
-+ if (ep->dwc_ep.type ==
-+ DWC_OTG_EP_TYPE_ISOC) {
-+ req->actual = 0;
-+ dwc_otg_request_done(ep, req, 0);
-+
-+ ep->dwc_ep.start_xfer_buff = 0;
-+ ep->dwc_ep.xfer_buff = 0;
-+ ep->dwc_ep.xfer_len = 0;
-+
-+ /* If there is a request in the queue start it. */
-+ start_next_request(ep);
-+ } else
-+ DWC_WARN
-+ ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
-+ ep->dwc_ep.num,
-+ (ep->dwc_ep.is_in ? "IN" : "OUT"),
-+ deptsiz.b.xfersize,
-+ deptsiz.b.pktcnt);
-+ }
-+ } else {
-+ dma_desc = ep->dwc_ep.desc_addr;
-+ byte_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+
-+#ifdef DWC_UTE_CFI
-+ CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
-+ ep->dwc_ep.buff_mode);
-+ if (ep->dwc_ep.buff_mode != BM_STANDARD) {
-+ int residue;
-+
-+ residue = cfi_calc_desc_residue(ep);
-+ if (residue < 0)
-+ return;
-+
-+ byte_count = residue;
-+ } else {
-+#endif
-+ for (i = 0; i < ep->dwc_ep.desc_cnt;
-+ ++i) {
-+ desc_sts = dma_desc->status;
-+ byte_count += desc_sts.b.bytes;
-+ dma_desc++;
-+ }
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ if (byte_count == 0) {
-+ ep->dwc_ep.xfer_count =
-+ ep->dwc_ep.total_len;
-+ is_last = 1;
-+ } else {
-+ DWC_WARN("Incomplete transfer\n");
-+ }
-+ }
-+ } else {
-+ if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "%d-%s len=%d xfersize=%d pktcnt=%d\n",
-+ ep->dwc_ep.num,
-+ ep->dwc_ep.is_in ? "IN" : "OUT",
-+ ep->dwc_ep.xfer_len,
-+ deptsiz.b.xfersize,
-+ deptsiz.b.pktcnt);
-+
-+ /* Check if the whole transfer was completed,
-+ * if no, setup transfer for next portion of data
-+ */
-+ if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
-+ dwc_otg_ep_start_transfer(core_if,
-+ &ep->dwc_ep);
-+ } else if (ep->dwc_ep.sent_zlp) {
-+ /*
-+ * This fragment of code should initiate 0
-+ * length trasfer in case if it is queued
-+ * a trasfer with size divisible to EPs max
-+ * packet size and with usb_request zero field
-+ * is set, which means that after data is transfered,
-+ * it is also should be transfered
-+ * a 0 length packet at the end. For Slave and
-+ * Buffer DMA modes in this case SW has
-+ * to initiate 2 transfers one with transfer size,
-+ * and the second with 0 size. For Desriptor
-+ * DMA mode SW is able to initiate a transfer,
-+ * which will handle all the packets including
-+ * the last 0 legth.
-+ */
-+ ep->dwc_ep.sent_zlp = 0;
-+ dwc_otg_ep_start_zl_transfer(core_if,
-+ &ep->dwc_ep);
-+ } else {
-+ is_last = 1;
-+ }
-+ } else {
-+ DWC_WARN
-+ ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
-+ ep->dwc_ep.num,
-+ (ep->dwc_ep.is_in ? "IN" : "OUT"),
-+ deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+ }
-+ }
-+ } else {
-+ dwc_otg_dev_out_ep_regs_t *out_ep_regs =
-+ dev_if->out_ep_regs[ep->dwc_ep.num];
-+ desc_sts.d32 = 0;
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable) {
-+ dma_desc = ep->dwc_ep.desc_addr;
-+ byte_count = 0;
-+ ep->dwc_ep.sent_zlp = 0;
-+
-+#ifdef DWC_UTE_CFI
-+ CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
-+ ep->dwc_ep.buff_mode);
-+ if (ep->dwc_ep.buff_mode != BM_STANDARD) {
-+ int residue;
-+ residue = cfi_calc_desc_residue(ep);
-+ if (residue < 0)
-+ return;
-+ byte_count = residue;
-+ } else {
-+#endif
-+
-+ for (i = 0; i < ep->dwc_ep.desc_cnt;
-+ ++i) {
-+ desc_sts = dma_desc->status;
-+ byte_count += desc_sts.b.bytes;
-+ dma_desc++;
-+ }
-+
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ /* Checking for interrupt Out transfers with not
-+ * dword aligned mps sizes
-+ */
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR &&
-+ (ep->dwc_ep.maxpacket%4)) {
-+ ep->dwc_ep.xfer_count =
-+ ep->dwc_ep.total_len - byte_count;
-+ if ((ep->dwc_ep.xfer_len %
-+ ep->dwc_ep.maxpacket)
-+ && (ep->dwc_ep.xfer_len /
-+ ep->dwc_ep.maxpacket <
-+ MAX_DMA_DESC_CNT))
-+ ep->dwc_ep.xfer_len -=
-+ (ep->dwc_ep.desc_cnt -
-+ 1) * ep->dwc_ep.maxpacket +
-+ ep->dwc_ep.xfer_len %
-+ ep->dwc_ep.maxpacket;
-+ else
-+ ep->dwc_ep.xfer_len -=
-+ ep->dwc_ep.desc_cnt *
-+ ep->dwc_ep.maxpacket;
-+ if (ep->dwc_ep.xfer_len > 0) {
-+ dwc_otg_ep_start_transfer
-+ (core_if, &ep->dwc_ep);
-+ } else {
-+ is_last = 1;
-+ }
-+ } else {
-+ ep->dwc_ep.xfer_count =
-+ ep->dwc_ep.total_len - byte_count +
-+ ((4 -
-+ (ep->dwc_ep.
-+ total_len & 0x3)) & 0x3);
-+ is_last = 1;
-+ }
-+ } else {
-+ deptsiz.d32 = 0;
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&out_ep_regs->doeptsiz);
-+
-+ byte_count = (ep->dwc_ep.xfer_len -
-+ ep->dwc_ep.xfer_count -
-+ deptsiz.b.xfersize);
-+ ep->dwc_ep.xfer_buff += byte_count;
-+ ep->dwc_ep.dma_addr += byte_count;
-+ ep->dwc_ep.xfer_count += byte_count;
-+
-+ /* Check if the whole transfer was completed,
-+ * if no, setup transfer for next portion of data
-+ */
-+ if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
-+ dwc_otg_ep_start_transfer(core_if,
-+ &ep->dwc_ep);
-+ } else if (ep->dwc_ep.sent_zlp) {
-+ /*
-+ * This fragment of code should initiate 0
-+ * length trasfer in case if it is queued
-+ * a trasfer with size divisible to EPs max
-+ * packet size and with usb_request zero field
-+ * is set, which means that after data is transfered,
-+ * it is also should be transfered
-+ * a 0 length packet at the end. For Slave and
-+ * Buffer DMA modes in this case SW has
-+ * to initiate 2 transfers one with transfer size,
-+ * and the second with 0 size. For Desriptor
-+ * DMA mode SW is able to initiate a transfer,
-+ * which will handle all the packets including
-+ * the last 0 legth.
-+ */
-+ ep->dwc_ep.sent_zlp = 0;
-+ dwc_otg_ep_start_zl_transfer(core_if,
-+ &ep->dwc_ep);
-+ } else {
-+ is_last = 1;
-+ }
-+ }
-+ } else {
-+ /* Check if the whole transfer was completed,
-+ * if no, setup transfer for next portion of data
-+ */
-+ if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
-+ dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
-+ } else if (ep->dwc_ep.sent_zlp) {
-+ /*
-+ * This fragment of code should initiate 0
-+ * length transfer in case if it is queued
-+ * a transfer with size divisible to EPs max
-+ * packet size and with usb_request zero field
-+ * is set, which means that after data is transfered,
-+ * it is also should be transfered
-+ * a 0 length packet at the end. For Slave and
-+ * Buffer DMA modes in this case SW has
-+ * to initiate 2 transfers one with transfer size,
-+ * and the second with 0 size. For Descriptor
-+ * DMA mode SW is able to initiate a transfer,
-+ * which will handle all the packets including
-+ * the last 0 length.
-+ */
-+ ep->dwc_ep.sent_zlp = 0;
-+ dwc_otg_ep_start_zl_transfer(core_if,
-+ &ep->dwc_ep);
-+ } else {
-+ is_last = 1;
-+ }
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
-+ &out_ep_regs->doeptsiz, ep->dwc_ep.num,
-+ ep->dwc_ep.is_in ? "IN" : "OUT",
-+ ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
-+ deptsiz.b.xfersize, deptsiz.b.pktcnt);
-+ }
-+
-+ /* Complete the request */
-+ if (is_last) {
-+#ifdef DWC_UTE_CFI
-+ if (ep->dwc_ep.buff_mode != BM_STANDARD) {
-+ req->actual = ep->dwc_ep.cfi_req_len - byte_count;
-+ } else {
-+#endif
-+ req->actual = ep->dwc_ep.xfer_count;
-+#ifdef DWC_UTE_CFI
-+ }
-+#endif
-+ if (req->dw_align_buf) {
-+ if (!ep->dwc_ep.is_in) {
-+ dwc_memcpy(req->buf, req->dw_align_buf, req->length);
-+ }
-+ DWC_DMA_FREE(req->length, req->dw_align_buf,
-+ req->dw_align_buf_dma);
-+ }
-+
-+ dwc_otg_request_done(ep, req, 0);
-+
-+ ep->dwc_ep.start_xfer_buff = 0;
-+ ep->dwc_ep.xfer_buff = 0;
-+ ep->dwc_ep.xfer_len = 0;
-+
-+ /* If there is a request in the queue start it. */
-+ start_next_request(ep);
-+ }
-+}
-+
-+#ifdef DWC_EN_ISOC
-+
-+/**
-+ * This function BNA interrupt for Isochronous EPs
-+ *
-+ */
-+static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_ep_t *dwc_ep = &ep->dwc_ep;
-+ volatile uint32_t *addr;
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dwc_otg_pcd_t *pcd = ep->pcd;
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ int i;
-+
-+ dma_desc =
-+ dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
-+
-+ if (dwc_ep->is_in) {
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
-+ sts.d32 = dma_desc->status.d32;
-+ sts.b_iso_in.bs = BS_HOST_READY;
-+ dma_desc->status.d32 = sts.d32;
-+ }
-+ } else {
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
-+ sts.d32 = dma_desc->status.d32;
-+ sts.b_iso_out.bs = BS_HOST_READY;
-+ dma_desc->status.d32 = sts.d32;
-+ }
-+ }
-+
-+ if (dwc_ep->is_in == 0) {
-+ addr =
-+ &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->
-+ num]->doepctl;
-+ } else {
-+ addr =
-+ &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
-+ }
-+ depctl.b.epena = 1;
-+ DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32);
-+}
-+
-+/**
-+ * This function sets latest iso packet information(non-PTI mode)
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ *
-+ */
-+void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+ dma_addr_t dma_addr;
-+ uint32_t offset;
-+
-+ if (ep->proc_buf_num)
-+ dma_addr = ep->dma_addr1;
-+ else
-+ dma_addr = ep->dma_addr0;
-+
-+ if (ep->is_in) {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->
-+ in_ep_regs[ep->num]->dieptsiz);
-+ offset = ep->data_per_frame;
-+ } else {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[ep->num]->doeptsiz);
-+ offset =
-+ ep->data_per_frame +
-+ (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
-+ }
-+
-+ if (!deptsiz.b.xfersize) {
-+ ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
-+ ep->pkt_info[ep->cur_pkt].offset =
-+ ep->cur_pkt_dma_addr - dma_addr;
-+ ep->pkt_info[ep->cur_pkt].status = 0;
-+ } else {
-+ ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
-+ ep->pkt_info[ep->cur_pkt].offset =
-+ ep->cur_pkt_dma_addr - dma_addr;
-+ ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
-+ }
-+ ep->cur_pkt_addr += offset;
-+ ep->cur_pkt_dma_addr += offset;
-+ ep->cur_pkt++;
-+}
-+
-+/**
-+ * This function sets latest iso packet information(DDMA mode)
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param dwc_ep The EP to start the transfer on.
-+ *
-+ */
-+static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * dwc_ep)
-+{
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ iso_pkt_info_t *iso_packet;
-+ uint32_t data_per_desc;
-+ uint32_t offset;
-+ int i, j;
-+
-+ iso_packet = dwc_ep->pkt_info;
-+
-+ /** Reinit closed DMA Descriptors*/
-+ /** ISO OUT EP */
-+ if (dwc_ep->is_in == 0) {
-+ dma_desc =
-+ dwc_ep->iso_desc_addr +
-+ dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
-+ offset = 0;
-+
-+ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
-+ i += dwc_ep->pkt_per_frm) {
-+ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->
-+ data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 -
-+ data_per_desc %
-+ 4) : 0;
-+
-+ sts.d32 = dma_desc->status.d32;
-+
-+ /* Write status in iso_packet_decsriptor */
-+ iso_packet->status =
-+ sts.b_iso_out.rxsts +
-+ (sts.b_iso_out.bs ^ BS_DMA_DONE);
-+ if (iso_packet->status) {
-+ iso_packet->status = -DWC_E_NO_DATA;
-+ }
-+
-+ /* Received data length */
-+ if (!sts.b_iso_out.rxbytes) {
-+ iso_packet->length =
-+ data_per_desc -
-+ sts.b_iso_out.rxbytes;
-+ } else {
-+ iso_packet->length =
-+ data_per_desc -
-+ sts.b_iso_out.rxbytes + (4 -
-+ dwc_ep->data_per_frame
-+ % 4);
-+ }
-+
-+ iso_packet->offset = offset;
-+
-+ offset += data_per_desc;
-+ dma_desc++;
-+ iso_packet++;
-+ }
-+ }
-+
-+ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
-+
-+ sts.d32 = dma_desc->status.d32;
-+
-+ /* Write status in iso_packet_decsriptor */
-+ iso_packet->status =
-+ sts.b_iso_out.rxsts +
-+ (sts.b_iso_out.bs ^ BS_DMA_DONE);
-+ if (iso_packet->status) {
-+ iso_packet->status = -DWC_E_NO_DATA;
-+ }
-+
-+ /* Received data length */
-+ iso_packet->length =
-+ dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
-+
-+ iso_packet->offset = offset;
-+
-+ offset += data_per_desc;
-+ iso_packet++;
-+ dma_desc++;
-+ }
-+
-+ sts.d32 = dma_desc->status.d32;
-+
-+ /* Write status in iso_packet_decsriptor */
-+ iso_packet->status =
-+ sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
-+ if (iso_packet->status) {
-+ iso_packet->status = -DWC_E_NO_DATA;
-+ }
-+ /* Received data length */
-+ if (!sts.b_iso_out.rxbytes) {
-+ iso_packet->length =
-+ dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
-+ } else {
-+ iso_packet->length =
-+ dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
-+ (4 - dwc_ep->data_per_frame % 4);
-+ }
-+
-+ iso_packet->offset = offset;
-+ } else {
-+/** ISO IN EP */
-+
-+ dma_desc =
-+ dwc_ep->iso_desc_addr +
-+ dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
-+
-+ for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
-+ sts.d32 = dma_desc->status.d32;
-+
-+ /* Write status in iso packet descriptor */
-+ iso_packet->status =
-+ sts.b_iso_in.txsts +
-+ (sts.b_iso_in.bs ^ BS_DMA_DONE);
-+ if (iso_packet->status != 0) {
-+ iso_packet->status = -DWC_E_NO_DATA;
-+
-+ }
-+ /* Bytes has been transfered */
-+ iso_packet->length =
-+ dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
-+
-+ dma_desc++;
-+ iso_packet++;
-+ }
-+
-+ sts.d32 = dma_desc->status.d32;
-+ while (sts.b_iso_in.bs == BS_DMA_BUSY) {
-+ sts.d32 = dma_desc->status.d32;
-+ }
-+
-+ /* Write status in iso packet descriptor ??? do be done with ERROR codes */
-+ iso_packet->status =
-+ sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
-+ if (iso_packet->status != 0) {
-+ iso_packet->status = -DWC_E_NO_DATA;
-+ }
-+
-+ /* Bytes has been transfered */
-+ iso_packet->length =
-+ dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
-+ }
-+}
-+
-+/**
-+ * This function reinitialize DMA Descriptors for Isochronous transfer
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param dwc_ep The EP to start the transfer on.
-+ *
-+ */
-+static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
-+{
-+ int i, j;
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ dma_addr_t dma_ad;
-+ volatile uint32_t *addr;
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ uint32_t data_per_desc;
-+
-+ if (dwc_ep->is_in == 0) {
-+ addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
-+ } else {
-+ addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
-+ }
-+
-+ if (dwc_ep->proc_buf_num == 0) {
-+ /** Buffer 0 descriptors setup */
-+ dma_ad = dwc_ep->dma_addr0;
-+ } else {
-+ /** Buffer 1 descriptors setup */
-+ dma_ad = dwc_ep->dma_addr1;
-+ }
-+
-+ /** Reinit closed DMA Descriptors*/
-+ /** ISO OUT EP */
-+ if (dwc_ep->is_in == 0) {
-+ dma_desc =
-+ dwc_ep->iso_desc_addr +
-+ dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
-+
-+ sts.b_iso_out.bs = BS_HOST_READY;
-+ sts.b_iso_out.rxsts = 0;
-+ sts.b_iso_out.l = 0;
-+ sts.b_iso_out.sp = 0;
-+ sts.b_iso_out.ioc = 0;
-+ sts.b_iso_out.pid = 0;
-+ sts.b_iso_out.framenum = 0;
-+
-+ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
-+ i += dwc_ep->pkt_per_frm) {
-+ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->
-+ data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 -
-+ data_per_desc %
-+ 4) : 0;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ dma_ad += data_per_desc;
-+ dma_desc++;
-+ }
-+ }
-+
-+ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
-+
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ dma_desc++;
-+ dma_ad += data_per_desc;
-+ }
-+
-+ sts.b_iso_out.ioc = 1;
-+ sts.b_iso_out.l = dwc_ep->proc_buf_num;
-+
-+ data_per_desc =
-+ ((j + 1) * dwc_ep->maxpacket >
-+ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
-+ j * dwc_ep->maxpacket : dwc_ep->maxpacket;
-+ data_per_desc +=
-+ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
-+ sts.b_iso_out.rxbytes = data_per_desc;
-+
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+ } else {
-+/** ISO IN EP */
-+
-+ dma_desc =
-+ dwc_ep->iso_desc_addr +
-+ dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
-+
-+ sts.b_iso_in.bs = BS_HOST_READY;
-+ sts.b_iso_in.txsts = 0;
-+ sts.b_iso_in.sp = 0;
-+ sts.b_iso_in.ioc = 0;
-+ sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
-+ sts.b_iso_in.framenum = dwc_ep->next_frame;
-+ sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
-+ sts.b_iso_in.l = 0;
-+
-+ for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ sts.b_iso_in.framenum += dwc_ep->bInterval;
-+ dma_ad += dwc_ep->data_per_frame;
-+ dma_desc++;
-+ }
-+
-+ sts.b_iso_in.ioc = 1;
-+ sts.b_iso_in.l = dwc_ep->proc_buf_num;
-+
-+ dma_desc->buf = dma_ad;
-+ dma_desc->status.d32 = sts.d32;
-+
-+ dwc_ep->next_frame =
-+ sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
-+ }
-+ dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
-+}
-+
-+/**
-+ * This function is to handle Iso EP transfer complete interrupt
-+ * in case Iso out packet was dropped
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param dwc_ep The EP for wihich transfer complete was asserted
-+ *
-+ */
-+static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
-+ dwc_ep_t * dwc_ep)
-+{
-+ uint32_t dma_addr;
-+ uint32_t drp_pkt;
-+ uint32_t drp_pkt_cnt;
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ int i;
-+
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[dwc_ep->num]->doeptsiz);
-+
-+ drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
-+ drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
-+
-+ /* Setting dropped packets status */
-+ for (i = 0; i < drp_pkt_cnt; ++i) {
-+ dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
-+ drp_pkt++;
-+ deptsiz.b.pktcnt--;
-+ }
-+
-+ if (deptsiz.b.pktcnt > 0) {
-+ deptsiz.b.xfersize =
-+ dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
-+ deptsiz.b.pktcnt) * dwc_ep->maxpacket;
-+ } else {
-+ deptsiz.b.xfersize = 0;
-+ deptsiz.b.pktcnt = 0;
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
-+ deptsiz.d32);
-+
-+ if (deptsiz.b.pktcnt > 0) {
-+ if (dwc_ep->proc_buf_num) {
-+ dma_addr =
-+ dwc_ep->dma_addr1 + dwc_ep->xfer_len -
-+ deptsiz.b.xfersize;
-+ } else {
-+ dma_addr =
-+ dwc_ep->dma_addr0 + dwc_ep->xfer_len -
-+ deptsiz.b.xfersize;;
-+ }
-+
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ out_ep_regs[dwc_ep->num]->doepdma, dma_addr);
-+
-+ /** Re-enable endpoint, clear nak */
-+ depctl.d32 = 0;
-+ depctl.b.epena = 1;
-+ depctl.b.cnak = 1;
-+
-+ DWC_MODIFY_REG32(&core_if->dev_if->
-+ out_ep_regs[dwc_ep->num]->doepctl, depctl.d32,
-+ depctl.d32);
-+ return 0;
-+ } else {
-+ return 1;
-+ }
-+}
-+
-+/**
-+ * This function sets iso packets information(PTI mode)
-+ *
-+ * @param core_if Programming view of DWC_otg controller.
-+ * @param ep The EP to start the transfer on.
-+ *
-+ */
-+static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
-+{
-+ int i, j;
-+ dma_addr_t dma_ad;
-+ iso_pkt_info_t *packet_info = ep->pkt_info;
-+ uint32_t offset;
-+ uint32_t frame_data;
-+ deptsiz_data_t deptsiz;
-+
-+ if (ep->proc_buf_num == 0) {
-+ /** Buffer 0 descriptors setup */
-+ dma_ad = ep->dma_addr0;
-+ } else {
-+ /** Buffer 1 descriptors setup */
-+ dma_ad = ep->dma_addr1;
-+ }
-+
-+ if (ep->is_in) {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
-+ dieptsiz);
-+ } else {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]->
-+ doeptsiz);
-+ }
-+
-+ if (!deptsiz.b.xfersize) {
-+ offset = 0;
-+ for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
-+ frame_data = ep->data_per_frame;
-+ for (j = 0; j < ep->pkt_per_frm; ++j) {
-+
-+ /* Packet status - is not set as initially
-+ * it is set to 0 and if packet was sent
-+ successfully, status field will remain 0*/
-+
-+ /* Bytes has been transfered */
-+ packet_info->length =
-+ (ep->maxpacket <
-+ frame_data) ? ep->maxpacket : frame_data;
-+
-+ /* Received packet offset */
-+ packet_info->offset = offset;
-+ offset += packet_info->length;
-+ frame_data -= packet_info->length;
-+
-+ packet_info++;
-+ }
-+ }
-+ return 1;
-+ } else {
-+ /* This is a workaround for in case of Transfer Complete with
-+ * PktDrpSts interrupts merging - in this case Transfer complete
-+ * interrupt for Isoc Out Endpoint is asserted without PktDrpSts
-+ * set and with DOEPTSIZ register non zero. Investigations showed,
-+ * that this happens when Out packet is dropped, but because of
-+ * interrupts merging during first interrupt handling PktDrpSts
-+ * bit is cleared and for next merged interrupts it is not reset.
-+ * In this case SW hadles the interrupt as if PktDrpSts bit is set.
-+ */
-+ if (ep->is_in) {
-+ return 1;
-+ } else {
-+ return handle_iso_out_pkt_dropped(core_if, ep);
-+ }
-+ }
-+}
-+
-+/**
-+ * This function is to handle Iso EP transfer complete interrupt
-+ *
-+ * @param pcd The PCD
-+ * @param ep The EP for which transfer complete was asserted
-+ *
-+ */
-+static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
-+ dwc_ep_t *dwc_ep = &ep->dwc_ep;
-+ uint8_t is_last = 0;
-+
-+ if (ep->dwc_ep.next_frame == 0xffffffff) {
-+ DWC_WARN("Next frame is not set!\n");
-+ return;
-+ }
-+
-+ if (core_if->dma_enable) {
-+ if (core_if->dma_desc_enable) {
-+ set_ddma_iso_pkts_info(core_if, dwc_ep);
-+ reinit_ddma_iso_xfer(core_if, dwc_ep);
-+ is_last = 1;
-+ } else {
-+ if (core_if->pti_enh_enable) {
-+ if (set_iso_pkts_info(core_if, dwc_ep)) {
-+ dwc_ep->proc_buf_num =
-+ (dwc_ep->proc_buf_num ^ 1) & 0x1;
-+ dwc_otg_iso_ep_start_buf_transfer
-+ (core_if, dwc_ep);
-+ is_last = 1;
-+ }
-+ } else {
-+ set_current_pkt_info(core_if, dwc_ep);
-+ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
-+ is_last = 1;
-+ dwc_ep->cur_pkt = 0;
-+ dwc_ep->proc_buf_num =
-+ (dwc_ep->proc_buf_num ^ 1) & 0x1;
-+ if (dwc_ep->proc_buf_num) {
-+ dwc_ep->cur_pkt_addr =
-+ dwc_ep->xfer_buff1;
-+ dwc_ep->cur_pkt_dma_addr =
-+ dwc_ep->dma_addr1;
-+ } else {
-+ dwc_ep->cur_pkt_addr =
-+ dwc_ep->xfer_buff0;
-+ dwc_ep->cur_pkt_dma_addr =
-+ dwc_ep->dma_addr0;
-+ }
-+
-+ }
-+ dwc_otg_iso_ep_start_frm_transfer(core_if,
-+ dwc_ep);
-+ }
-+ }
-+ } else {
-+ set_current_pkt_info(core_if, dwc_ep);
-+ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
-+ is_last = 1;
-+ dwc_ep->cur_pkt = 0;
-+ dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
-+ if (dwc_ep->proc_buf_num) {
-+ dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
-+ dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
-+ } else {
-+ dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
-+ dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
-+ }
-+
-+ }
-+ dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
-+ }
-+ if (is_last)
-+ dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
-+}
-+#endif /* DWC_EN_ISOC */
-+
-+/**
-+ * This function handle BNA interrupt for Non Isochronous EPs
-+ *
-+ */
-+static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep)
-+{
-+ dwc_ep_t *dwc_ep = &ep->dwc_ep;
-+ volatile uint32_t *addr;
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dwc_otg_pcd_t *pcd = ep->pcd;
-+ dwc_otg_dev_dma_desc_t *dma_desc;
-+ dev_dma_desc_sts_t sts = {.d32 = 0 };
-+ dwc_otg_core_if_t *core_if = ep->pcd->core_if;
-+ int i, start;
-+
-+ if (!dwc_ep->desc_cnt)
-+ DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num,
-+ (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt);
-+
-+ if (core_if->core_params->cont_on_bna && !dwc_ep->is_in
-+ && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) {
-+ uint32_t doepdma;
-+ dwc_otg_dev_out_ep_regs_t *out_regs =
-+ core_if->dev_if->out_ep_regs[dwc_ep->num];
-+ doepdma = DWC_READ_REG32(&(out_regs->doepdma));
-+ start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t);
-+ dma_desc = &(dwc_ep->desc_addr[start]);
-+ } else {
-+ start = 0;
-+ dma_desc = dwc_ep->desc_addr;
-+ }
-+
-+
-+ for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
-+ sts.d32 = dma_desc->status.d32;
-+ sts.b.bs = BS_HOST_READY;
-+ dma_desc->status.d32 = sts.d32;
-+ }
-+
-+ if (dwc_ep->is_in == 0) {
-+ addr =
-+ &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
-+ doepctl;
-+ } else {
-+ addr =
-+ &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
-+ }
-+ depctl.b.epena = 1;
-+ depctl.b.cnak = 1;
-+ DWC_MODIFY_REG32(addr, 0, depctl.d32);
-+}
-+
-+/**
-+ * This function handles EP0 Control transfers.
-+ *
-+ * The state of the control transfers are tracked in
-+ * <code>ep0state</code>.
-+ */
-+static void handle_ep0(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
-+ dev_dma_desc_sts_t desc_sts;
-+ deptsiz0_data_t deptsiz;
-+ uint32_t byte_count;
-+
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
-+ print_ep0_state(pcd);
-+#endif
-+
-+// DWC_PRINTF("HANDLE EP0\n");
-+
-+ switch (pcd->ep0state) {
-+ case EP0_DISCONNECT:
-+ break;
-+
-+ case EP0_IDLE:
-+ pcd->request_config = 0;
-+
-+ pcd_setup(pcd);
-+ break;
-+
-+ case EP0_IN_DATA_PHASE:
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
-+ ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
-+ ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
-+#endif
-+
-+ if (core_if->dma_enable != 0) {
-+ /*
-+ * For EP0 we can only program 1 packet at a time so we
-+ * need to do the make calculations after each complete.
-+ * Call write_packet to make the calculations, as in
-+ * slave mode, and use those values to determine if we
-+ * can complete.
-+ */
-+ if (core_if->dma_desc_enable == 0) {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->
-+ dev_if->in_ep_regs[0]->
-+ dieptsiz);
-+ byte_count =
-+ ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
-+ } else {
-+ desc_sts =
-+ core_if->dev_if->in_desc_addr->status;
-+ byte_count =
-+ ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
-+ }
-+ ep0->dwc_ep.xfer_count += byte_count;
-+ ep0->dwc_ep.xfer_buff += byte_count;
-+ ep0->dwc_ep.dma_addr += byte_count;
-+ }
-+ if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
-+ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
-+ &ep0->dwc_ep);
-+ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
-+ } else if (ep0->dwc_ep.sent_zlp) {
-+ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
-+ &ep0->dwc_ep);
-+ ep0->dwc_ep.sent_zlp = 0;
-+ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
-+ } else {
-+ ep0_complete_request(ep0);
-+ DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
-+ }
-+ break;
-+ case EP0_OUT_DATA_PHASE:
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
-+ ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
-+ ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
-+#endif
-+ if (core_if->dma_enable != 0) {
-+ if (core_if->dma_desc_enable == 0) {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->
-+ dev_if->out_ep_regs[0]->
-+ doeptsiz);
-+ byte_count =
-+ ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
-+ } else {
-+ desc_sts =
-+ core_if->dev_if->out_desc_addr->status;
-+ byte_count =
-+ ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
-+ }
-+ ep0->dwc_ep.xfer_count += byte_count;
-+ ep0->dwc_ep.xfer_buff += byte_count;
-+ ep0->dwc_ep.dma_addr += byte_count;
-+ }
-+ if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
-+ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
-+ &ep0->dwc_ep);
-+ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
-+ } else if (ep0->dwc_ep.sent_zlp) {
-+ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
-+ &ep0->dwc_ep);
-+ ep0->dwc_ep.sent_zlp = 0;
-+ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n");
-+ } else {
-+ ep0_complete_request(ep0);
-+ DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
-+ }
-+ break;
-+
-+ case EP0_IN_STATUS_PHASE:
-+ case EP0_OUT_STATUS_PHASE:
-+ DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
-+ ep0_complete_request(ep0);
-+ pcd->ep0state = EP0_IDLE;
-+ ep0->stopped = 1;
-+ ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
-+
-+ /* Prepare for more SETUP Packets */
-+ if (core_if->dma_enable) {
-+ ep0_out_start(core_if, pcd);
-+ }
-+ break;
-+
-+ case EP0_STALL:
-+ DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
-+ break;
-+ }
-+#ifdef DEBUG_EP0
-+ print_ep0_state(pcd);
-+#endif
-+}
-+
-+/**
-+ * Restart transfer
-+ */
-+static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
-+{
-+ dwc_otg_core_if_t *core_if;
-+ dwc_otg_dev_if_t *dev_if;
-+ deptsiz_data_t dieptsiz = {.d32 = 0 };
-+ dwc_otg_pcd_ep_t *ep;
-+
-+ ep = get_in_ep(pcd, epnum);
-+
-+#ifdef DWC_EN_ISOC
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ return;
-+ }
-+#endif /* DWC_EN_ISOC */
-+
-+ core_if = GET_CORE_IF(pcd);
-+ dev_if = core_if->dev_if;
-+
-+ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
-+
-+ DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
-+ " stopped=%d\n", ep->dwc_ep.xfer_buff,
-+ ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
-+ /*
-+ * If xfersize is 0 and pktcnt in not 0, resend the last packet.
-+ */
-+ if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
-+ ep->dwc_ep.start_xfer_buff != 0) {
-+ if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
-+ ep->dwc_ep.xfer_count = 0;
-+ ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
-+ ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
-+ } else {
-+ ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
-+ /* convert packet size to dwords. */
-+ ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
-+ ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
-+ }
-+ ep->stopped = 0;
-+ DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
-+ "xfer_len=%0x stopped=%d\n",
-+ ep->dwc_ep.xfer_buff,
-+ ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
-+ ep->stopped);
-+ if (epnum == 0) {
-+ dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
-+ } else {
-+ dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
-+ }
-+ }
-+}
-+
-+/*
-+ * This function create new nextep sequnce based on Learn Queue.
-+ *
-+ * @param core_if Programming view of DWC_otg controller
-+ */
-+void predict_nextep_seq( dwc_otg_core_if_t * core_if)
-+{
-+ dwc_otg_device_global_regs_t *dev_global_regs =
-+ core_if->dev_if->dev_global_regs;
-+ const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
-+ /* Number of Token Queue Registers */
-+ const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
-+ dtknq1_data_t dtknqr1;
-+ uint32_t in_tkn_epnums[4];
-+ uint8_t seqnum[MAX_EPS_CHANNELS];
-+ uint8_t intkn_seq[TOKEN_Q_DEPTH];
-+ grstctl_t resetctl = {.d32 = 0 };
-+ uint8_t temp;
-+ int ndx = 0;
-+ int start = 0;
-+ int end = 0;
-+ int sort_done = 0;
-+ int i = 0;
-+ volatile uint32_t *addr = &dev_global_regs->dtknqr1;
-+
-+
-+ DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
-+
-+ /* Read the DTKNQ Registers */
-+ for (i = 0; i < DTKNQ_REG_CNT; i++) {
-+ in_tkn_epnums[i] = DWC_READ_REG32(addr);
-+ DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
-+ in_tkn_epnums[i]);
-+ if (addr == &dev_global_regs->dvbusdis) {
-+ addr = &dev_global_regs->dtknqr3_dthrctl;
-+ } else {
-+ ++addr;
-+ }
-+
-+ }
-+
-+ /* Copy the DTKNQR1 data to the bit field. */
-+ dtknqr1.d32 = in_tkn_epnums[0];
-+ if (dtknqr1.b.wrap_bit) {
-+ ndx = dtknqr1.b.intknwptr;
-+ end = ndx -1;
-+ if (end < 0)
-+ end = TOKEN_Q_DEPTH -1;
-+ } else {
-+ ndx = 0;
-+ end = dtknqr1.b.intknwptr -1;
-+ if (end < 0)
-+ end = 0;
-+ }
-+ start = ndx;
-+
-+ /* Fill seqnum[] by initial values: EP number + 31 */
-+ for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
-+ seqnum[i] = i +31;
-+ }
-+
-+ /* Fill intkn_seq[] from in_tkn_epnums[0] */
-+ for (i=0; i < 6; i++)
-+ intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf;
-+
-+ if (TOKEN_Q_DEPTH > 6) {
-+ /* Fill intkn_seq[] from in_tkn_epnums[1] */
-+ for (i=6; i < 14; i++)
-+ intkn_seq[i] =
-+ (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf;
-+ }
-+
-+ if (TOKEN_Q_DEPTH > 14) {
-+ /* Fill intkn_seq[] from in_tkn_epnums[1] */
-+ for (i=14; i < 22; i++)
-+ intkn_seq[i] =
-+ (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf;
-+ }
-+
-+ if (TOKEN_Q_DEPTH > 22) {
-+ /* Fill intkn_seq[] from in_tkn_epnums[1] */
-+ for (i=22; i < 30; i++)
-+ intkn_seq[i] =
-+ (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf;
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__,
-+ start, end);
-+ for (i=0; i<TOKEN_Q_DEPTH; i++)
-+ DWC_DEBUGPL(DBG_PCDV,"%d\n", intkn_seq[i]);
-+
-+ /* Update seqnum based on intkn_seq[] */
-+ i = 0;
-+ do {
-+ seqnum[intkn_seq[ndx]] = i;
-+ ndx++;
-+ i++;
-+ if (ndx == TOKEN_Q_DEPTH)
-+ ndx = 0;
-+ } while ( i < TOKEN_Q_DEPTH );
-+
-+ /* Mark non active EP's in seqnum[] by 0xff */
-+ for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
-+ if (core_if->nextep_seq[i] == 0xff )
-+ seqnum[i] = 0xff;
-+ }
-+
-+ /* Sort seqnum[] */
-+ sort_done = 0;
-+ while (!sort_done) {
-+ sort_done = 1;
-+ for (i=0; i<core_if->dev_if->num_in_eps; i++) {
-+ if (seqnum[i] > seqnum[i+1]) {
-+ temp = seqnum[i];
-+ seqnum[i] = seqnum[i+1];
-+ seqnum[i+1] = temp;
-+ sort_done = 0;
-+ }
-+ }
-+ }
-+
-+ ndx = start + seqnum[0];
-+ if (ndx >= TOKEN_Q_DEPTH)
-+ ndx = ndx % TOKEN_Q_DEPTH;
-+ core_if->first_in_nextep_seq = intkn_seq[ndx];
-+
-+ /* Update seqnum[] by EP numbers */
-+ for (i=0; i<=core_if->dev_if->num_in_eps; i++) {
-+ ndx = start + i;
-+ if (seqnum[i] < 31) {
-+ ndx = start + seqnum[i];
-+ if (ndx >= TOKEN_Q_DEPTH)
-+ ndx = ndx % TOKEN_Q_DEPTH;
-+ seqnum[i] = intkn_seq[ndx];
-+ } else {
-+ if (seqnum[i] < 0xff) {
-+ seqnum[i] = seqnum[i] - 31;
-+ } else {
-+ break;
-+ }
-+ }
-+ }
-+
-+ /* Update nextep_seq[] based on seqnum[] */
-+ for (i=0; i<core_if->dev_if->num_in_eps; i++) {
-+ if (seqnum[i] != 0xff) {
-+ if (seqnum[i+1] != 0xff) {
-+ core_if->nextep_seq[seqnum[i]] = seqnum[i+1];
-+ } else {
-+ core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq;
-+ break;
-+ }
-+ } else {
-+ break;
-+ }
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
-+ __func__, core_if->first_in_nextep_seq);
-+ for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
-+ DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]);
-+ }
-+
-+ /* Flush the Learning Queue */
-+ resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl);
-+ resetctl.b.intknqflsh = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
-+
-+
-+}
-+
-+/**
-+ * handle the IN EP disable interrupt.
-+ */
-+static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
-+ const uint32_t epnum)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ deptsiz_data_t dieptsiz = {.d32 = 0 };
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+ gintmsk_data_t gintmsk_data;
-+ depctl_data_t depctl;
-+ uint32_t diepdma;
-+ uint32_t remain_to_transfer = 0;
-+ uint8_t i;
-+ uint32_t xfer_size;
-+
-+ ep = get_in_ep(pcd, epnum);
-+ dwc_ep = &ep->dwc_ep;
-+
-+ if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
-+ complete_ep(ep);
-+ return;
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
-+ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl));
-+ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz);
-+ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
-+
-+ DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
-+ dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
-+
-+ if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) {
-+ if (ep->stopped) {
-+ if (core_if->en_multiple_tx_fifo)
-+ /* Flush the Tx FIFO */
-+ dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
-+ /* Clear the Global IN NP NAK */
-+ dctl.d32 = 0;
-+ dctl.b.cgnpinnak = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
-+ /* Restart the transaction */
-+ if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
-+ restart_transfer(pcd, epnum);
-+ }
-+ } else {
-+ /* Restart the transaction */
-+ if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
-+ restart_transfer(pcd, epnum);
-+ }
-+ DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
-+ }
-+ return;
-+ }
-+
-+ if (core_if->start_predict > 2) { // NP IN EP
-+ core_if->start_predict--;
-+ return;
-+ }
-+
-+ core_if->start_predict--;
-+
-+ if (core_if->start_predict == 1) { // All NP IN Ep's disabled now
-+
-+ predict_nextep_seq(core_if);
-+
-+ /* Update all active IN EP's NextEP field based of nextep_seq[] */
-+ for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) {
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP
-+ depctl.b.nextep = core_if->nextep_seq[i];
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
-+ }
-+ }
-+ /* Flush Shared NP TxFIFO */
-+ dwc_otg_flush_tx_fifo(core_if, 0);
-+ /* Rewind buffers */
-+ if (!core_if->dma_desc_enable) {
-+ i = core_if->first_in_nextep_seq;
-+ do {
-+ ep = get_in_ep(pcd, i);
-+ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
-+ xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count;
-+ if (xfer_size > ep->dwc_ep.maxxfer)
-+ xfer_size = ep->dwc_ep.maxxfer;
-+ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ if (dieptsiz.b.pktcnt != 0) {
-+ if (xfer_size == 0) {
-+ remain_to_transfer = 0;
-+ } else {
-+ if ((xfer_size % ep->dwc_ep.maxpacket) == 0) {
-+ remain_to_transfer =
-+ dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket;
-+ } else {
-+ remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket)
-+ + (xfer_size % ep->dwc_ep.maxpacket);
-+ }
-+ }
-+ diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma);
-+ dieptsiz.b.xfersize = remain_to_transfer;
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32);
-+ diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer);
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma);
-+ }
-+ i = core_if->nextep_seq[i];
-+ } while (i != core_if->first_in_nextep_seq);
-+ } else { // dma_desc_enable
-+ DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__);
-+ }
-+
-+ /* Restart transfers in predicted sequences */
-+ i = core_if->first_in_nextep_seq;
-+ do {
-+ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
-+ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ if (dieptsiz.b.pktcnt != 0) {
-+ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ depctl.b.epena = 1;
-+ depctl.b.cnak = 1;
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
-+ }
-+ i = core_if->nextep_seq[i];
-+ } while (i != core_if->first_in_nextep_seq);
-+
-+ /* Clear the global non-periodic IN NAK handshake */
-+ dctl.d32 = 0;
-+ dctl.b.cgnpinnak = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
-+
-+ /* Unmask EP Mismatch interrupt */
-+ gintmsk_data.d32 = 0;
-+ gintmsk_data.b.epmismatch = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32);
-+
-+ core_if->start_predict = 0;
-+
-+ }
-+}
-+
-+/**
-+ * Handler for the IN EP timeout handshake interrupt.
-+ */
-+static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
-+ const uint32_t epnum)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+
-+#ifdef DEBUG
-+ deptsiz_data_t dieptsiz = {.d32 = 0 };
-+ uint32_t num = 0;
-+#endif
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dwc_otg_pcd_ep_t *ep;
-+
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ ep = get_in_ep(pcd, epnum);
-+
-+ /* Disable the NP Tx Fifo Empty Interrrupt */
-+ if (!core_if->dma_enable) {
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+ }
-+ /** @todo NGS Check EP type.
-+ * Implement for Periodic EPs */
-+ /*
-+ * Non-periodic EP
-+ */
-+ /* Enable the Global IN NAK Effective Interrupt */
-+ intr_mask.b.ginnakeff = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
-+
-+ /* Set Global IN NAK */
-+ dctl.b.sgnpinnak = 1;
-+ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
-+
-+ ep->stopped = 1;
-+
-+#ifdef DEBUG
-+ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz);
-+ DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
-+ dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
-+#endif
-+
-+#ifdef DISABLE_PERIODIC_EP
-+ /*
-+ * Set the NAK bit for this EP to
-+ * start the disable process.
-+ */
-+ diepctl.d32 = 0;
-+ diepctl.b.snak = 1;
-+ DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
-+ diepctl.d32);
-+ ep->disabling = 1;
-+ ep->stopped = 1;
-+#endif
-+}
-+
-+/**
-+ * Handler for the IN EP NAK interrupt.
-+ */
-+static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
-+ const uint32_t epnum)
-+{
-+ /** @todo implement ISR */
-+ dwc_otg_core_if_t *core_if;
-+ diepmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
-+ core_if = GET_CORE_IF(pcd);
-+ intr_mask.b.nak = 1;
-+
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ diepeachintmsk[epnum], intr_mask.d32, 0);
-+ } else {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk,
-+ intr_mask.d32, 0);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handler for the OUT EP Babble interrupt.
-+ */
-+static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
-+ const uint32_t epnum)
-+{
-+ /** @todo implement ISR */
-+ dwc_otg_core_if_t *core_if;
-+ doepmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
-+ "OUT EP Babble");
-+ core_if = GET_CORE_IF(pcd);
-+ intr_mask.b.babble = 1;
-+
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ doepeachintmsk[epnum], intr_mask.d32, 0);
-+ } else {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
-+ intr_mask.d32, 0);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handler for the OUT EP NAK interrupt.
-+ */
-+static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
-+ const uint32_t epnum)
-+{
-+ /** @todo implement ISR */
-+ dwc_otg_core_if_t *core_if;
-+ doepmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
-+ core_if = GET_CORE_IF(pcd);
-+ intr_mask.b.nak = 1;
-+
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ doepeachintmsk[epnum], intr_mask.d32, 0);
-+ } else {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
-+ intr_mask.d32, 0);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * Handler for the OUT EP NYET interrupt.
-+ */
-+static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
-+ const uint32_t epnum)
-+{
-+ /** @todo implement ISR */
-+ dwc_otg_core_if_t *core_if;
-+ doepmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
-+ core_if = GET_CORE_IF(pcd);
-+ intr_mask.b.nyet = 1;
-+
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
-+ doepeachintmsk[epnum], intr_mask.d32, 0);
-+ } else {
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
-+ intr_mask.d32, 0);
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * This interrupt indicates that an IN EP has a pending Interrupt.
-+ * The sequence for handling the IN EP interrupt is shown below:
-+ * -# Read the Device All Endpoint Interrupt register
-+ * -# Repeat the following for each IN EP interrupt bit set (from
-+ * LSB to MSB).
-+ * -# Read the Device Endpoint Interrupt (DIEPINTn) register
-+ * -# If "Transfer Complete" call the request complete function
-+ * -# If "Endpoint Disabled" complete the EP disable procedure.
-+ * -# If "AHB Error Interrupt" log error
-+ * -# If "Time-out Handshake" log error
-+ * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
-+ * FIFO.
-+ * -# If "IN Token EP Mismatch" (disable, this is handled by EP
-+ * Mismatch Interrupt)
-+ */
-+static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
-+{
-+#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
-+do { \
-+ diepint_data_t diepint = {.d32=0}; \
-+ diepint.b.__intr = 1; \
-+ DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
-+ diepint.d32); \
-+} while (0)
-+
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
-+ diepint_data_t diepint = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ uint32_t ep_intr;
-+ uint32_t epnum = 0;
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
-+
-+ /* Read in the device interrupt bits */
-+ ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
-+
-+ /* Service the Device IN interrupts for each endpoint */
-+ while (ep_intr) {
-+ if (ep_intr & 0x1) {
-+ uint32_t empty_msk;
-+ /* Get EP pointer */
-+ ep = get_in_ep(pcd, epnum);
-+ dwc_ep = &ep->dwc_ep;
-+
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
-+ empty_msk =
-+ DWC_READ_REG32(&dev_if->
-+ dev_global_regs->dtknqr4_fifoemptymsk);
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",
-+ epnum, empty_msk, depctl.d32);
-+
-+ DWC_DEBUGPL(DBG_PCD,
-+ "EP%d-%s: type=%d, mps=%d\n",
-+ dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
-+ dwc_ep->type, dwc_ep->maxpacket);
-+
-+ diepint.d32 =
-+ dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
-+
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "EP %d Interrupt Register - 0x%x\n", epnum,
-+ diepint.d32);
-+ /* Transfer complete */
-+ if (diepint.b.xfercompl) {
-+ /* Disable the NP Tx FIFO Empty
-+ * Interrupt */
-+ if (core_if->en_multiple_tx_fifo == 0) {
-+ intr_mask.b.nptxfempty = 1;
-+ DWC_MODIFY_REG32
-+ (&core_if->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+ } else {
-+ /* Disable the Tx FIFO Empty Interrupt for this EP */
-+ uint32_t fifoemptymsk =
-+ 0x1 << dwc_ep->num;
-+ DWC_MODIFY_REG32(&core_if->
-+ dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
-+ fifoemptymsk, 0);
-+ }
-+ /* Clear the bit in DIEPINTn for this interrupt */
-+ CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
-+
-+ /* Complete the transfer */
-+ if (epnum == 0) {
-+ handle_ep0(pcd);
-+ }
-+#ifdef DWC_EN_ISOC
-+ else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ if (!ep->stopped)
-+ complete_iso_ep(pcd, ep);
-+ }
-+#endif /* DWC_EN_ISOC */
-+#ifdef DWC_UTE_PER_IO
-+ else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ if (!ep->stopped)
-+ complete_xiso_ep(ep);
-+ }
-+#endif /* DWC_UTE_PER_IO */
-+ else {
-+ if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC &&
-+ dwc_ep->bInterval > 1) {
-+ dwc_ep->frame_num += dwc_ep->bInterval;
-+ if (dwc_ep->frame_num > 0x3FFF)
-+ {
-+ dwc_ep->frm_overrun = 1;
-+ dwc_ep->frame_num &= 0x3FFF;
-+ } else
-+ dwc_ep->frm_overrun = 0;
-+ }
-+ complete_ep(ep);
-+ if(diepint.b.nak)
-+ CLEAR_IN_EP_INTR(core_if, epnum, nak);
-+ }
-+ }
-+ /* Endpoint disable */
-+ if (diepint.b.epdisabled) {
-+ DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
-+ epnum);
-+ handle_in_ep_disable_intr(pcd, epnum);
-+
-+ /* Clear the bit in DIEPINTn for this interrupt */
-+ CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
-+ }
-+ /* AHB Error */
-+ if (diepint.b.ahberr) {
-+ DWC_ERROR("EP%d IN AHB Error\n", epnum);
-+ /* Clear the bit in DIEPINTn for this interrupt */
-+ CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
-+ }
-+ /* TimeOUT Handshake (non-ISOC IN EPs) */
-+ if (diepint.b.timeout) {
-+ DWC_ERROR("EP%d IN Time-out\n", epnum);
-+ handle_in_ep_timeout_intr(pcd, epnum);
-+
-+ CLEAR_IN_EP_INTR(core_if, epnum, timeout);
-+ }
-+ /** IN Token received with TxF Empty */
-+ if (diepint.b.intktxfemp) {
-+ DWC_DEBUGPL(DBG_ANY,
-+ "EP%d IN TKN TxFifo Empty\n",
-+ epnum);
-+ if (!ep->stopped && epnum != 0) {
-+
-+ diepmsk_data_t diepmsk = {.d32 = 0 };
-+ diepmsk.b.intktxfemp = 1;
-+
-+ if (core_if->multiproc_int_enable) {
-+ DWC_MODIFY_REG32
-+ (&dev_if->dev_global_regs->diepeachintmsk
-+ [epnum], diepmsk.d32, 0);
-+ } else {
-+ DWC_MODIFY_REG32
-+ (&dev_if->dev_global_regs->diepmsk,
-+ diepmsk.d32, 0);
-+ }
-+ } else if (core_if->dma_desc_enable
-+ && epnum == 0
-+ && pcd->ep0state ==
-+ EP0_OUT_STATUS_PHASE) {
-+ // EP0 IN set STALL
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs
-+ [epnum]->diepctl);
-+
-+ /* set the disable and stall bits */
-+ if (depctl.b.epena) {
-+ depctl.b.epdis = 1;
-+ }
-+ depctl.b.stall = 1;
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs
-+ [epnum]->diepctl,
-+ depctl.d32);
-+ }
-+ CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
-+ }
-+ /** IN Token Received with EP mismatch */
-+ if (diepint.b.intknepmis) {
-+ DWC_DEBUGPL(DBG_ANY,
-+ "EP%d IN TKN EP Mismatch\n", epnum);
-+ CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
-+ }
-+ /** IN Endpoint NAK Effective */
-+ if (diepint.b.inepnakeff) {
-+ DWC_DEBUGPL(DBG_ANY,
-+ "EP%d IN EP NAK Effective\n",
-+ epnum);
-+ /* Periodic EP */
-+ if (ep->disabling) {
-+ depctl.d32 = 0;
-+ depctl.b.snak = 1;
-+ depctl.b.epdis = 1;
-+ DWC_MODIFY_REG32(&dev_if->in_ep_regs
-+ [epnum]->diepctl,
-+ depctl.d32,
-+ depctl.d32);
-+ }
-+ CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
-+
-+ }
-+
-+ /** IN EP Tx FIFO Empty Intr */
-+ if (diepint.b.emptyintr) {
-+ DWC_DEBUGPL(DBG_ANY,
-+ "EP%d Tx FIFO Empty Intr \n",
-+ epnum);
-+ write_empty_tx_fifo(pcd, epnum);
-+
-+ CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
-+
-+ }
-+
-+ /** IN EP BNA Intr */
-+ if (diepint.b.bna) {
-+ CLEAR_IN_EP_INTR(core_if, epnum, bna);
-+ if (core_if->dma_desc_enable) {
-+#ifdef DWC_EN_ISOC
-+ if (dwc_ep->type ==
-+ DWC_OTG_EP_TYPE_ISOC) {
-+ /*
-+ * This checking is performed to prevent first "false" BNA
-+ * handling occuring right after reconnect
-+ */
-+ if (dwc_ep->next_frame !=
-+ 0xffffffff)
-+ dwc_otg_pcd_handle_iso_bna(ep);
-+ } else
-+#endif /* DWC_EN_ISOC */
-+ {
-+ dwc_otg_pcd_handle_noniso_bna(ep);
-+ }
-+ }
-+ }
-+ /* NAK Interrutp */
-+ if (diepint.b.nak) {
-+ DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
-+ epnum);
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ depctl_data_t depctl;
-+ if (ep->dwc_ep.frame_num == 0xFFFFFFFF) {
-+ ep->dwc_ep.frame_num = core_if->frame_num;
-+ if (ep->dwc_ep.bInterval > 1) {
-+ depctl.d32 = 0;
-+ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl);
-+ if (ep->dwc_ep.frame_num & 0x1) {
-+ depctl.b.setd1pid = 1;
-+ depctl.b.setd0pid = 0;
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ depctl.b.setd1pid = 0;
-+ }
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32);
-+ }
-+ start_next_request(ep);
-+ }
-+ ep->dwc_ep.frame_num += ep->dwc_ep.bInterval;
-+ if (dwc_ep->frame_num > 0x3FFF) {
-+ dwc_ep->frm_overrun = 1;
-+ dwc_ep->frame_num &= 0x3FFF;
-+ } else
-+ dwc_ep->frm_overrun = 0;
-+ }
-+
-+ CLEAR_IN_EP_INTR(core_if, epnum, nak);
-+ }
-+ }
-+ epnum++;
-+ ep_intr >>= 1;
-+ }
-+
-+ return 1;
-+#undef CLEAR_IN_EP_INTR
-+}
-+
-+/**
-+ * This interrupt indicates that an OUT EP has a pending Interrupt.
-+ * The sequence for handling the OUT EP interrupt is shown below:
-+ * -# Read the Device All Endpoint Interrupt register
-+ * -# Repeat the following for each OUT EP interrupt bit set (from
-+ * LSB to MSB).
-+ * -# Read the Device Endpoint Interrupt (DOEPINTn) register
-+ * -# If "Transfer Complete" call the request complete function
-+ * -# If "Endpoint Disabled" complete the EP disable procedure.
-+ * -# If "AHB Error Interrupt" log error
-+ * -# If "Setup Phase Done" process Setup Packet (See Standard USB
-+ * Command Processing)
-+ */
-+static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
-+{
-+#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
-+do { \
-+ doepint_data_t doepint = {.d32=0}; \
-+ doepint.b.__intr = 1; \
-+ DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
-+ doepint.d32); \
-+} while (0)
-+
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ uint32_t ep_intr;
-+ doepint_data_t doepint = {.d32 = 0 };
-+ uint32_t epnum = 0;
-+ dwc_otg_pcd_ep_t *ep;
-+ dwc_ep_t *dwc_ep;
-+ dctl_data_t dctl = {.d32 = 0 };
-+ gintmsk_data_t gintmsk = {.d32 = 0 };
-+
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
-+
-+ /* Read in the device interrupt bits */
-+ ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
-+
-+ while (ep_intr) {
-+ if (ep_intr & 0x1) {
-+ /* Get EP pointer */
-+ ep = get_out_ep(pcd, epnum);
-+ dwc_ep = &ep->dwc_ep;
-+
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "EP%d-%s: type=%d, mps=%d\n",
-+ dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
-+ dwc_ep->type, dwc_ep->maxpacket);
-+#endif
-+ doepint.d32 =
-+ dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
-+ /* Moved this interrupt upper due to core deffect of asserting
-+ * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */
-+ if (doepint.b.stsphsercvd) {
-+ deptsiz0_data_t deptsiz;
-+ CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[0]->doeptsiz);
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a
-+ && core_if->dma_enable
-+ && core_if->dma_desc_enable == 0
-+ && doepint.b.xfercompl
-+ && deptsiz.b.xfersize == 24) {
-+ CLEAR_OUT_EP_INTR(core_if, epnum,
-+ xfercompl);
-+ doepint.b.xfercompl = 0;
-+ ep0_out_start(core_if, pcd);
-+ }
-+ if ((core_if->dma_desc_enable) ||
-+ (core_if->dma_enable
-+ && core_if->snpsid >=
-+ OTG_CORE_REV_3_00a)) {
-+ do_setup_in_status_phase(pcd);
-+ }
-+ }
-+ /* Transfer complete */
-+ if (doepint.b.xfercompl) {
-+
-+ if (epnum == 0) {
-+ /* Clear the bit in DOEPINTn for this interrupt */
-+ CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
-+ DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
-+ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint),
-+ doepint.d32);
-+ DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n",
-+ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl));
-+
-+ if (core_if->snpsid >= OTG_CORE_REV_3_00a
-+ && core_if->dma_enable == 0) {
-+ doepint_data_t doepint;
-+ doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[0]->doepint);
-+ if (pcd->ep0state == EP0_IDLE && doepint.b.sr) {
-+ CLEAR_OUT_EP_INTR(core_if, epnum, sr);
-+ goto exit_xfercompl;
-+ }
-+ }
-+ /* In case of DDMA look at SR bit to go to the Data Stage */
-+ if (core_if->dma_desc_enable) {
-+ dev_dma_desc_sts_t status = {.d32 = 0};
-+ if (pcd->ep0state == EP0_IDLE) {
-+ status.d32 = core_if->dev_if->setup_desc_addr[core_if->
-+ dev_if->setup_desc_index]->status.d32;
-+ if(pcd->data_terminated) {
-+ pcd->data_terminated = 0;
-+ status.d32 = core_if->dev_if->out_desc_addr->status.d32;
-+ dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8);
-+ }
-+ if (status.b.sr) {
-+ if (doepint.b.setup) {
-+ DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n");
-+ /* Already started data stage, clear setup */
-+ CLEAR_OUT_EP_INTR(core_if, epnum, setup);
-+ doepint.b.setup = 0;
-+ handle_ep0(pcd);
-+ /* Prepare for more setup packets */
-+ if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
-+ pcd->ep0state == EP0_IN_DATA_PHASE) {
-+ ep0_out_start(core_if, pcd);
-+ }
-+
-+ goto exit_xfercompl;
-+ } else {
-+ /* Prepare for more setup packets */
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "EP0_IDLE SR=1 setup=0 new setup comes\n");
-+ ep0_out_start(core_if, pcd);
-+ }
-+ }
-+ } else {
-+ dwc_otg_pcd_request_t *req;
-+ dev_dma_desc_sts_t status = {.d32 = 0};
-+ diepint_data_t diepint0;
-+ diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint);
-+
-+ if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) {
-+ DWC_ERROR("EP0 is stalled/disconnected\n");
-+ }
-+
-+ /* Clear IN xfercompl if set */
-+ if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE
-+ || pcd->ep0state == EP0_IN_DATA_PHASE)) {
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint, diepint0.d32);
-+ }
-+
-+ status.d32 = core_if->dev_if->setup_desc_addr[core_if->
-+ dev_if->setup_desc_index]->status.d32;
-+
-+ if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len
-+ && (pcd->ep0state == EP0_OUT_DATA_PHASE))
-+ status.d32 = core_if->dev_if->out_desc_addr->status.d32;
-+ if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
-+ status.d32 = core_if->dev_if->
-+ out_desc_addr->status.d32;
-+
-+ if (status.b.sr) {
-+ if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
-+ } else {
-+ DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
-+ pcd->ep0state == EP0_OUT_DATA_PHASE) {
-+ /* Read arrived setup packet from req->buf */
-+ dwc_memcpy(&pcd->setup_pkt->req,
-+ req->buf + ep->dwc_ep.xfer_count, 8);
-+ }
-+ req->actual = ep->dwc_ep.xfer_count;
-+ dwc_otg_request_done(ep, req, -ECONNRESET);
-+ ep->dwc_ep.start_xfer_buff = 0;
-+ ep->dwc_ep.xfer_buff = 0;
-+ ep->dwc_ep.xfer_len = 0;
-+ }
-+ pcd->ep0state = EP0_IDLE;
-+ if (doepint.b.setup) {
-+ DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
-+ /* Data stage started, clear setup */
-+ CLEAR_OUT_EP_INTR(core_if, epnum, setup);
-+ doepint.b.setup = 0;
-+ handle_ep0(pcd);
-+ /* Prepare for setup packets if ep0in was enabled*/
-+ if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
-+ ep0_out_start(core_if, pcd);
-+ }
-+
-+ goto exit_xfercompl;
-+ } else {
-+ /* Prepare for more setup packets */
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
-+ ep0_out_start(core_if, pcd);
-+ }
-+ }
-+ }
-+ }
-+ if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable
-+ && core_if->dma_desc_enable == 0) {
-+ doepint_data_t doepint_temp = {.d32 = 0};
-+ deptsiz0_data_t doeptsize0 = {.d32 = 0 };
-+ doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[ep->dwc_ep.num]->doepint);
-+ doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[ep->dwc_ep.num]->doeptsiz);
-+ if (pcd->ep0state == EP0_IDLE) {
-+ if (doepint_temp.b.sr) {
-+ CLEAR_OUT_EP_INTR(core_if, epnum, sr);
-+ }
-+ doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[0]->doepint);
-+ if (doeptsize0.b.supcnt == 3) {
-+ DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n");
-+ ep->dwc_ep.stp_rollover = 1;
-+ }
-+ if (doepint.b.setup) {
-+retry:
-+ /* Already started data stage, clear setup */
-+ CLEAR_OUT_EP_INTR(core_if, epnum, setup);
-+ doepint.b.setup = 0;
-+ handle_ep0(pcd);
-+ ep->dwc_ep.stp_rollover = 0;
-+ /* Prepare for more setup packets */
-+ if (pcd->ep0state == EP0_IN_STATUS_PHASE ||
-+ pcd->ep0state == EP0_IN_DATA_PHASE) {
-+ ep0_out_start(core_if, pcd);
-+ }
-+ goto exit_xfercompl;
-+ } else {
-+ /* Prepare for more setup packets */
-+ DWC_DEBUGPL(DBG_ANY,
-+ "EP0_IDLE SR=1 setup=0 new setup comes\n");
-+ doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[0]->doepint);
-+ if(doepint.b.setup)
-+ goto retry;
-+ ep0_out_start(core_if, pcd);
-+ }
-+ } else {
-+ dwc_otg_pcd_request_t *req;
-+ diepint_data_t diepint0 = {.d32 = 0};
-+ doepint_data_t doepint_temp = {.d32 = 0};
-+ depctl_data_t diepctl0;
-+ diepint0.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint);
-+ diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepctl);
-+
-+ if (pcd->ep0state == EP0_IN_DATA_PHASE
-+ || pcd->ep0state == EP0_IN_STATUS_PHASE) {
-+ if (diepint0.b.xfercompl) {
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint, diepint0.d32);
-+ }
-+ if (diepctl0.b.epena) {
-+ diepint_data_t diepint = {.d32 = 0};
-+ diepctl0.b.snak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepctl, diepctl0.d32);
-+ do {
-+ dwc_udelay(10);
-+ diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint);
-+ } while (!diepint.b.inepnakeff);
-+ diepint.b.inepnakeff = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint, diepint.d32);
-+ diepctl0.d32 = 0;
-+ diepctl0.b.epdis = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl,
-+ diepctl0.d32);
-+ do {
-+ dwc_udelay(10);
-+ diepint.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ in_ep_regs[0]->diepint);
-+ } while (!diepint.b.epdisabled);
-+ diepint.b.epdisabled = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint,
-+ diepint.d32);
-+ }
-+ }
-+ doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[ep->dwc_ep.num]->doepint);
-+ if (doepint_temp.b.sr) {
-+ CLEAR_OUT_EP_INTR(core_if, epnum, sr);
-+ if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n");
-+ } else {
-+ DWC_DEBUGPL(DBG_PCDV, "complete req!!\n");
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len &&
-+ pcd->ep0state == EP0_OUT_DATA_PHASE) {
-+ /* Read arrived setup packet from req->buf */
-+ dwc_memcpy(&pcd->setup_pkt->req,
-+ req->buf + ep->dwc_ep.xfer_count, 8);
-+ }
-+ req->actual = ep->dwc_ep.xfer_count;
-+ dwc_otg_request_done(ep, req, -ECONNRESET);
-+ ep->dwc_ep.start_xfer_buff = 0;
-+ ep->dwc_ep.xfer_buff = 0;
-+ ep->dwc_ep.xfer_len = 0;
-+ }
-+ pcd->ep0state = EP0_IDLE;
-+ if (doepint.b.setup) {
-+ DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n");
-+ /* Data stage started, clear setup */
-+ CLEAR_OUT_EP_INTR(core_if, epnum, setup);
-+ doepint.b.setup = 0;
-+ handle_ep0(pcd);
-+ /* Prepare for setup packets if ep0in was enabled*/
-+ if (pcd->ep0state == EP0_IN_STATUS_PHASE) {
-+ ep0_out_start(core_if, pcd);
-+ }
-+ goto exit_xfercompl;
-+ } else {
-+ /* Prepare for more setup packets */
-+ DWC_DEBUGPL(DBG_PCDV,
-+ "EP0_IDLE SR=1 setup=0 new setup comes 2\n");
-+ ep0_out_start(core_if, pcd);
-+ }
-+ }
-+ }
-+ }
-+ if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE)
-+ handle_ep0(pcd);
-+exit_xfercompl:
-+ DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n",
-+ dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32);
-+ } else {
-+ if (core_if->dma_desc_enable == 0
-+ || pcd->ep0state != EP0_IDLE)
-+ handle_ep0(pcd);
-+ }
-+#ifdef DWC_EN_ISOC
-+ } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ if (doepint.b.pktdrpsts == 0) {
-+ /* Clear the bit in DOEPINTn for this interrupt */
-+ CLEAR_OUT_EP_INTR(core_if,
-+ epnum,
-+ xfercompl);
-+ complete_iso_ep(pcd, ep);
-+ } else {
-+
-+ doepint_data_t doepint = {.d32 = 0 };
-+ doepint.b.xfercompl = 1;
-+ doepint.b.pktdrpsts = 1;
-+ DWC_WRITE_REG32
-+ (&core_if->dev_if->out_ep_regs
-+ [epnum]->doepint,
-+ doepint.d32);
-+ if (handle_iso_out_pkt_dropped
-+ (core_if, dwc_ep)) {
-+ complete_iso_ep(pcd,
-+ ep);
-+ }
-+ }
-+#endif /* DWC_EN_ISOC */
-+#ifdef DWC_UTE_PER_IO
-+ } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl);
-+ if (!ep->stopped)
-+ complete_xiso_ep(ep);
-+#endif /* DWC_UTE_PER_IO */
-+ } else {
-+ /* Clear the bit in DOEPINTn for this interrupt */
-+ CLEAR_OUT_EP_INTR(core_if, epnum,
-+ xfercompl);
-+
-+ if (core_if->core_params->dev_out_nak) {
-+ DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]);
-+ pcd->core_if->ep_xfer_info[epnum].state = 0;
-+#ifdef DEBUG
-+ print_memory_payload(pcd, dwc_ep);
-+#endif
-+ }
-+ complete_ep(ep);
-+ }
-+
-+ }
-+
-+ /* Endpoint disable */
-+ if (doepint.b.epdisabled) {
-+
-+ /* Clear the bit in DOEPINTn for this interrupt */
-+ CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
-+ if (core_if->core_params->dev_out_nak) {
-+#ifdef DEBUG
-+ print_memory_payload(pcd, dwc_ep);
-+#endif
-+ /* In case of timeout condition */
-+ if (core_if->ep_xfer_info[epnum].state == 2) {
-+ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->dctl);
-+ dctl.b.cgoutnak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
-+ dctl.d32);
-+ /* Unmask goutnakeff interrupt which was masked
-+ * during handle nak out interrupt */
-+ gintmsk.b.goutnakeff = 1;
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
-+ 0, gintmsk.d32);
-+
-+ complete_ep(ep);
-+ }
-+ }
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC)
-+ {
-+ dctl_data_t dctl;
-+ gintmsk_data_t intr_mask = {.d32 = 0};
-+ dwc_otg_pcd_request_t *req = 0;
-+
-+ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ dev_global_regs->dctl);
-+ dctl.b.cgoutnak = 1;
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
-+ dctl.d32);
-+
-+ intr_mask.d32 = 0;
-+ intr_mask.b.incomplisoout = 1;
-+
-+ /* Get any pending requests */
-+ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
-+ req = DWC_CIRCLEQ_FIRST(&ep->queue);
-+ if (!req) {
-+ DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
-+ } else {
-+ dwc_otg_request_done(ep, req, 0);
-+ start_next_request(ep);
-+ }
-+ } else {
-+ DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
-+ }
-+ }
-+ }
-+ /* AHB Error */
-+ if (doepint.b.ahberr) {
-+ DWC_ERROR("EP%d OUT AHB Error\n", epnum);
-+ DWC_ERROR("EP%d DEPDMA=0x%08x \n",
-+ epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma);
-+ CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
-+ }
-+ /* Setup Phase Done (contorl EPs) */
-+ if (doepint.b.setup) {
-+#ifdef DEBUG_EP0
-+ DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum);
-+#endif
-+ CLEAR_OUT_EP_INTR(core_if, epnum, setup);
-+
-+ handle_ep0(pcd);
-+ }
-+
-+ /** OUT EP BNA Intr */
-+ if (doepint.b.bna) {
-+ CLEAR_OUT_EP_INTR(core_if, epnum, bna);
-+ if (core_if->dma_desc_enable) {
-+#ifdef DWC_EN_ISOC
-+ if (dwc_ep->type ==
-+ DWC_OTG_EP_TYPE_ISOC) {
-+ /*
-+ * This checking is performed to prevent first "false" BNA
-+ * handling occuring right after reconnect
-+ */
-+ if (dwc_ep->next_frame !=
-+ 0xffffffff)
-+ dwc_otg_pcd_handle_iso_bna(ep);
-+ } else
-+#endif /* DWC_EN_ISOC */
-+ {
-+ dwc_otg_pcd_handle_noniso_bna(ep);
-+ }
-+ }
-+ }
-+ /* Babble Interrupt */
-+ if (doepint.b.babble) {
-+ DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
-+ epnum);
-+ handle_out_ep_babble_intr(pcd, epnum);
-+
-+ CLEAR_OUT_EP_INTR(core_if, epnum, babble);
-+ }
-+ if (doepint.b.outtknepdis) {
-+ DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \
-+ disabled\n",epnum);
-+ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ doepmsk_data_t doepmsk = {.d32 = 0};
-+ ep->dwc_ep.frame_num = core_if->frame_num;
-+ if (ep->dwc_ep.bInterval > 1) {
-+ depctl_data_t depctl;
-+ depctl.d32 = DWC_READ_REG32(&core_if->dev_if->
-+ out_ep_regs[epnum]->doepctl);
-+ if (ep->dwc_ep.frame_num & 0x1) {
-+ depctl.b.setd1pid = 1;
-+ depctl.b.setd0pid = 0;
-+ } else {
-+ depctl.b.setd0pid = 1;
-+ depctl.b.setd1pid = 0;
-+ }
-+ DWC_WRITE_REG32(&core_if->dev_if->
-+ out_ep_regs[epnum]->doepctl, depctl.d32);
-+ }
-+ start_next_request(ep);
-+ doepmsk.b.outtknepdis = 1;
-+ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk,
-+ doepmsk.d32, 0);
-+ }
-+ CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis);
-+ }
-+
-+ /* NAK Interrutp */
-+ if (doepint.b.nak) {
-+ DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
-+ handle_out_ep_nak_intr(pcd, epnum);
-+
-+ CLEAR_OUT_EP_INTR(core_if, epnum, nak);
-+ }
-+ /* NYET Interrutp */
-+ if (doepint.b.nyet) {
-+ DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
-+ handle_out_ep_nyet_intr(pcd, epnum);
-+
-+ CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
-+ }
-+ }
-+
-+ epnum++;
-+ ep_intr >>= 1;
-+ }
-+
-+ return 1;
-+
-+#undef CLEAR_OUT_EP_INTR
-+}
-+static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun)
-+{
-+ int retval = 0;
-+ if(!frm_overrun && curr_fr >= trgt_fr)
-+ retval = 1;
-+ else if (frm_overrun
-+ && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2)))
-+ retval = 1;
-+ return retval;
-+}
-+/**
-+ * Incomplete ISO IN Transfer Interrupt.
-+ * This interrupt indicates one of the following conditions occurred
-+ * while transmitting an ISOC transaction.
-+ * - Corrupted IN Token for ISOC EP.
-+ * - Packet not complete in FIFO.
-+ * The follow actions will be taken:
-+ * -# Determine the EP
-+ * -# Set incomplete flag in dwc_ep structure
-+ * -# Disable EP; when "Endpoint Disabled" interrupt is received
-+ * Flush FIFO
-+ */
-+int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
-+{
-+ gintsts_data_t gintsts;
-+
-+#ifdef DWC_EN_ISOC
-+ dwc_otg_dev_if_t *dev_if;
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dsts_data_t dsts = {.d32 = 0 };
-+ dwc_ep_t *dwc_ep;
-+ int i;
-+
-+ dev_if = GET_CORE_IF(pcd)->dev_if;
-+
-+ for (i = 1; i <= dev_if->num_in_eps; ++i) {
-+ dwc_ep = &pcd->in_ep[i].dwc_ep;
-+ if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz);
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+
-+ if (depctl.b.epdis && deptsiz.d32) {
-+ set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
-+ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
-+ dwc_ep->cur_pkt = 0;
-+ dwc_ep->proc_buf_num =
-+ (dwc_ep->proc_buf_num ^ 1) & 0x1;
-+
-+ if (dwc_ep->proc_buf_num) {
-+ dwc_ep->cur_pkt_addr =
-+ dwc_ep->xfer_buff1;
-+ dwc_ep->cur_pkt_dma_addr =
-+ dwc_ep->dma_addr1;
-+ } else {
-+ dwc_ep->cur_pkt_addr =
-+ dwc_ep->xfer_buff0;
-+ dwc_ep->cur_pkt_dma_addr =
-+ dwc_ep->dma_addr0;
-+ }
-+
-+ }
-+
-+ dsts.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
-+ dev_global_regs->dsts);
-+ dwc_ep->next_frame = dsts.b.soffn;
-+
-+ dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
-+ (pcd),
-+ dwc_ep);
-+ }
-+ }
-+ }
-+
-+#else
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dwc_ep_t *dwc_ep;
-+ dwc_otg_dev_if_t *dev_if;
-+ int i;
-+ dev_if = GET_CORE_IF(pcd)->dev_if;
-+
-+ DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n");
-+
-+ for (i = 1; i <= dev_if->num_in_eps; ++i) {
-+ dwc_ep = &pcd->in_ep[i-1].dwc_ep;
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
-+ if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num,
-+ dwc_ep->frm_overrun))
-+ {
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ depctl.b.snak = 1;
-+ depctl.b.epdis = 1;
-+ DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32);
-+ }
-+ }
-+ }
-+
-+ /*intr_mask.b.incomplisoin = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0); */
-+#endif //DWC_EN_ISOC
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.incomplisoin = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * Incomplete ISO OUT Transfer Interrupt.
-+ *
-+ * This interrupt indicates that the core has dropped an ISO OUT
-+ * packet. The following conditions can be the cause:
-+ * - FIFO Full, the entire packet would not fit in the FIFO.
-+ * - CRC Error
-+ * - Corrupted Token
-+ * The follow actions will be taken:
-+ * -# Determine the EP
-+ * -# Set incomplete flag in dwc_ep structure
-+ * -# Read any data from the FIFO
-+ * -# Disable EP. When "Endpoint Disabled" interrupt is received
-+ * re-enable EP.
-+ */
-+int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
-+{
-+
-+ gintsts_data_t gintsts;
-+
-+#ifdef DWC_EN_ISOC
-+ dwc_otg_dev_if_t *dev_if;
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dsts_data_t dsts = {.d32 = 0 };
-+ dwc_ep_t *dwc_ep;
-+ int i;
-+
-+ dev_if = GET_CORE_IF(pcd)->dev_if;
-+
-+ for (i = 1; i <= dev_if->num_out_eps; ++i) {
-+ dwc_ep = &pcd->in_ep[i].dwc_ep;
-+ if (pcd->out_ep[i].dwc_ep.active &&
-+ pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz);
-+ depctl.d32 =
-+ DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
-+
-+ if (depctl.b.epdis && deptsiz.d32) {
-+ set_current_pkt_info(GET_CORE_IF(pcd),
-+ &pcd->out_ep[i].dwc_ep);
-+ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
-+ dwc_ep->cur_pkt = 0;
-+ dwc_ep->proc_buf_num =
-+ (dwc_ep->proc_buf_num ^ 1) & 0x1;
-+
-+ if (dwc_ep->proc_buf_num) {
-+ dwc_ep->cur_pkt_addr =
-+ dwc_ep->xfer_buff1;
-+ dwc_ep->cur_pkt_dma_addr =
-+ dwc_ep->dma_addr1;
-+ } else {
-+ dwc_ep->cur_pkt_addr =
-+ dwc_ep->xfer_buff0;
-+ dwc_ep->cur_pkt_dma_addr =
-+ dwc_ep->dma_addr0;
-+ }
-+
-+ }
-+
-+ dsts.d32 =
-+ DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if->
-+ dev_global_regs->dsts);
-+ dwc_ep->next_frame = dsts.b.soffn;
-+
-+ dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
-+ (pcd),
-+ dwc_ep);
-+ }
-+ }
-+ }
-+#else
-+ /** @todo implement ISR */
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ dwc_otg_core_if_t *core_if;
-+ deptsiz_data_t deptsiz = {.d32 = 0 };
-+ depctl_data_t depctl = {.d32 = 0 };
-+ dctl_data_t dctl = {.d32 = 0 };
-+ dwc_ep_t *dwc_ep = NULL;
-+ int i;
-+ core_if = GET_CORE_IF(pcd);
-+
-+ for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
-+ dwc_ep = &pcd->out_ep[i].dwc_ep;
-+ depctl.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
-+ if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) {
-+ core_if->dev_if->isoc_ep = dwc_ep;
-+ deptsiz.d32 =
-+ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz);
-+ break;
-+ }
-+ }
-+ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+
-+ if (!intr_mask.b.goutnakeff) {
-+ /* Unmask it */
-+ intr_mask.b.goutnakeff = 1;
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32);
-+ }
-+ if (!gintsts.b.goutnakeff) {
-+ dctl.b.sgoutnak = 1;
-+ }
-+ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
-+
-+ depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl);
-+ if (depctl.b.epena) {
-+ depctl.b.epdis = 1;
-+ depctl.b.snak = 1;
-+ }
-+ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32);
-+
-+ intr_mask.d32 = 0;
-+ intr_mask.b.incomplisoout = 1;
-+
-+#endif /* DWC_EN_ISOC */
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.incomplisoout = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * This function handles the Global IN NAK Effective interrupt.
-+ *
-+ */
-+int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
-+ depctl_data_t diepctl = {.d32 = 0 };
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+ int i;
-+
-+ DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
-+
-+ /* Disable all active IN EPs */
-+ for (i = 0; i <= dev_if->num_in_eps; i++) {
-+ diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
-+ if (!(diepctl.b.eptype & 1) && diepctl.b.epena) {
-+ if (core_if->start_predict > 0)
-+ core_if->start_predict++;
-+ diepctl.b.epdis = 1;
-+ diepctl.b.snak = 1;
-+ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32);
-+ }
-+ }
-+
-+
-+ /* Disable the Global IN NAK Effective Interrupt */
-+ intr_mask.b.ginnakeff = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.ginnakeff = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * OUT NAK Effective.
-+ *
-+ */
-+int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
-+ gintmsk_data_t intr_mask = {.d32 = 0 };
-+ gintsts_data_t gintsts;
-+ depctl_data_t doepctl;
-+ int i;
-+
-+ /* Disable the Global OUT NAK Effective Interrupt */
-+ intr_mask.b.goutnakeff = 1;
-+ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
-+ intr_mask.d32, 0);
-+
-+ /* If DEV OUT NAK enabled*/
-+ if (pcd->core_if->core_params->dev_out_nak) {
-+ /* Run over all out endpoints to determine the ep number on
-+ * which the timeout has happened
-+ */
-+ for (i = 0; i <= dev_if->num_out_eps; i++) {
-+ if ( pcd->core_if->ep_xfer_info[i].state == 2 )
-+ break;
-+ }
-+ if (i > dev_if->num_out_eps) {
-+ dctl_data_t dctl;
-+ dctl.d32 =
-+ DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
-+ dctl.b.cgoutnak = 1;
-+ DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl,
-+ dctl.d32);
-+ goto out;
-+ }
-+
-+ /* Disable the endpoint */
-+ doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
-+ if (doepctl.b.epena) {
-+ doepctl.b.epdis = 1;
-+ doepctl.b.snak = 1;
-+ }
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
-+ return 1;
-+ }
-+ /* We come here from Incomplete ISO OUT handler */
-+ if (dev_if->isoc_ep) {
-+ dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep;
-+ uint32_t epnum = dwc_ep->num;
-+ doepint_data_t doepint;
-+ doepint.d32 =
-+ DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint);
-+ dev_if->isoc_ep = NULL;
-+ doepctl.d32 =
-+ DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl);
-+ DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32);
-+ if (doepctl.b.epena) {
-+ doepctl.b.epdis = 1;
-+ doepctl.b.snak = 1;
-+ }
-+ DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl,
-+ doepctl.d32);
-+ return 1;
-+ } else
-+ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
-+ "Global OUT NAK Effective\n");
-+
-+out:
-+ /* Clear interrupt */
-+ gintsts.d32 = 0;
-+ gintsts.b.goutnakeff = 1;
-+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
-+ gintsts.d32);
-+
-+ return 1;
-+}
-+
-+/**
-+ * PCD interrupt handler.
-+ *
-+ * The PCD handles the device interrupts. Many conditions can cause a
-+ * device interrupt. When an interrupt occurs, the device interrupt
-+ * service routine determines the cause of the interrupt and
-+ * dispatches handling to the appropriate function. These interrupt
-+ * handling functions are described below.
-+ *
-+ * All interrupt registers are processed from LSB to MSB.
-+ *
-+ */
-+int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
-+{
-+ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
-+#ifdef VERBOSE
-+ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-+#endif
-+ gintsts_data_t gintr_status;
-+ int32_t retval = 0;
-+
-+ /* Exit from ISR if core is hibernated */
-+ if (core_if->hibernation_suspend == 1) {
-+ return retval;
-+ }
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
-+ __func__,
-+ DWC_READ_REG32(&global_regs->gintsts),
-+ DWC_READ_REG32(&global_regs->gintmsk));
-+#endif
-+
-+ if (dwc_otg_is_device_mode(core_if)) {
-+ DWC_SPINLOCK(pcd->lock);
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
-+ __func__,
-+ DWC_READ_REG32(&global_regs->gintsts),
-+ DWC_READ_REG32(&global_regs->gintmsk));
-+#endif
-+
-+ gintr_status.d32 = dwc_otg_read_core_intr(core_if);
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
-+ __func__, gintr_status.d32);
-+
-+ if (gintr_status.b.sofintr) {
-+ retval |= dwc_otg_pcd_handle_sof_intr(pcd);
-+ }
-+ if (gintr_status.b.rxstsqlvl) {
-+ retval |=
-+ dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
-+ }
-+ if (gintr_status.b.nptxfempty) {
-+ retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
-+ }
-+ if (gintr_status.b.goutnakeff) {
-+ retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
-+ }
-+ if (gintr_status.b.i2cintr) {
-+ retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
-+ }
-+ if (gintr_status.b.erlysuspend) {
-+ retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
-+ }
-+ if (gintr_status.b.usbreset) {
-+ retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
-+ }
-+ if (gintr_status.b.enumdone) {
-+ retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
-+ }
-+ if (gintr_status.b.isooutdrop) {
-+ retval |=
-+ dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
-+ (pcd);
-+ }
-+ if (gintr_status.b.eopframe) {
-+ retval |=
-+ dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
-+ }
-+ if (gintr_status.b.inepint) {
-+ if (!core_if->multiproc_int_enable) {
-+ retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
-+ }
-+ }
-+ if (gintr_status.b.outepintr) {
-+ if (!core_if->multiproc_int_enable) {
-+ retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
-+ }
-+ }
-+ if (gintr_status.b.epmismatch) {
-+ retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd);
-+ }
-+ if (gintr_status.b.fetsusp) {
-+ retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd);
-+ }
-+ if (gintr_status.b.ginnakeff) {
-+ retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
-+ }
-+ if (gintr_status.b.incomplisoin) {
-+ retval |=
-+ dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
-+ }
-+ if (gintr_status.b.incomplisoout) {
-+ retval |=
-+ dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
-+ }
-+
-+ /* In MPI mode Device Endpoints interrupts are asserted
-+ * without setting outepintr and inepint bits set, so these
-+ * Interrupt handlers are called without checking these bit-fields
-+ */
-+ if (core_if->multiproc_int_enable) {
-+ retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
-+ retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
-+ }
-+#ifdef VERBOSE
-+ DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
-+ DWC_READ_REG32(&global_regs->gintsts));
-+#endif
-+ DWC_SPINUNLOCK(pcd->lock);
-+ }
-+ return retval;
-+}
-+
-+#endif /* DWC_HOST_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,1358 @@
-+ /* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
-+ * $Revision: #21 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+#ifndef DWC_HOST_ONLY
-+
-+/** @file
-+ * This file implements the Peripheral Controller Driver.
-+ *
-+ * The Peripheral Controller Driver (PCD) is responsible for
-+ * translating requests from the Function Driver into the appropriate
-+ * actions on the DWC_otg controller. It isolates the Function Driver
-+ * from the specifics of the controller by providing an API to the
-+ * Function Driver.
-+ *
-+ * The Peripheral Controller Driver for Linux will implement the
-+ * Gadget API, so that the existing Gadget drivers can be used.
-+ * (Gadget Driver is the Linux terminology for a Function Driver.)
-+ *
-+ * The Linux Gadget API is defined in the header file
-+ * <code><linux/usb_gadget.h></code>. The USB EP operations API is
-+ * defined in the structure <code>usb_ep_ops</code> and the USB
-+ * Controller API is defined in the structure
-+ * <code>usb_gadget_ops</code>.
-+ *
-+ */
-+
-+#include "dwc_otg_os_dep.h"
-+#include "dwc_otg_pcd_if.h"
-+#include "dwc_otg_pcd.h"
-+#include "dwc_otg_driver.h"
-+#include "dwc_otg_dbg.h"
-+
-+static struct gadget_wrapper {
-+ dwc_otg_pcd_t *pcd;
-+
-+ struct usb_gadget gadget;
-+ struct usb_gadget_driver *driver;
-+
-+ struct usb_ep ep0;
-+ struct usb_ep in_ep[16];
-+ struct usb_ep out_ep[16];
-+
-+} *gadget_wrapper;
-+
-+/* Display the contents of the buffer */
-+extern void dump_msg(const u8 * buf, unsigned int length);
-+/**
-+ * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
-+ * if the endpoint is not found
-+ */
-+static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
-+{
-+ int i;
-+ if (pcd->ep0.priv == handle) {
-+ return &pcd->ep0;
-+ }
-+
-+ for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
-+ if (pcd->in_ep[i].priv == handle)
-+ return &pcd->in_ep[i];
-+ if (pcd->out_ep[i].priv == handle)
-+ return &pcd->out_ep[i];
-+ }
-+
-+ return NULL;
-+}
-+
-+/* USB Endpoint Operations */
-+/*
-+ * The following sections briefly describe the behavior of the Gadget
-+ * API endpoint operations implemented in the DWC_otg driver
-+ * software. Detailed descriptions of the generic behavior of each of
-+ * these functions can be found in the Linux header file
-+ * include/linux/usb_gadget.h.
-+ *
-+ * The Gadget API provides wrapper functions for each of the function
-+ * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
-+ * function, which then calls the underlying PCD function. The
-+ * following sections are named according to the wrapper
-+ * functions. Within each section, the corresponding DWC_otg PCD
-+ * function name is specified.
-+ *
-+ */
-+
-+/**
-+ * This function is called by the Gadget Driver for each EP to be
-+ * configured for the current configuration (SET_CONFIGURATION).
-+ *
-+ * This function initializes the dwc_otg_ep_t data structure, and then
-+ * calls dwc_otg_ep_activate.
-+ */
-+static int ep_enable(struct usb_ep *usb_ep,
-+ const struct usb_endpoint_descriptor *ep_desc)
-+{
-+ int retval;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
-+
-+ if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
-+ DWC_WARN("%s, bad ep or descriptor\n", __func__);
-+ return -EINVAL;
-+ }
-+ if (usb_ep == &gadget_wrapper->ep0) {
-+ DWC_WARN("%s, bad ep(0)\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ /* Check FIFO size? */
-+ if (!ep_desc->wMaxPacketSize) {
-+ DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
-+ return -ERANGE;
-+ }
-+
-+ if (!gadget_wrapper->driver ||
-+ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
-+ DWC_WARN("%s, bogus device state\n", __func__);
-+ return -ESHUTDOWN;
-+ }
-+
-+ /* Delete after check - MAS */
-+#if 0
-+ nat = (uint32_t) ep_desc->wMaxPacketSize;
-+ printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
-+ nat = (nat >> 11) & 0x03;
-+ printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
-+#endif
-+ retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
-+ (const uint8_t *)ep_desc,
-+ (void *)usb_ep);
-+ if (retval) {
-+ DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
-+ return -EINVAL;
-+ }
-+
-+ usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function is called when an EP is disabled due to disconnect or
-+ * change in configuration. Any pending requests will terminate with a
-+ * status of -ESHUTDOWN.
-+ *
-+ * This function modifies the dwc_otg_ep_t data structure for this EP,
-+ * and then calls dwc_otg_ep_deactivate.
-+ */
-+static int ep_disable(struct usb_ep *usb_ep)
-+{
-+ int retval;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
-+ if (!usb_ep) {
-+ DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
-+ usb_ep ? usb_ep->name : NULL);
-+ return -EINVAL;
-+ }
-+
-+ retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
-+ if (retval) {
-+ retval = -EINVAL;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function allocates a request object to use with the specified
-+ * endpoint.
-+ *
-+ * @param ep The endpoint to be used with with the request
-+ * @param gfp_flags the GFP_* flags to use.
-+ */
-+static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
-+ gfp_t gfp_flags)
-+{
-+ struct usb_request *usb_req;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
-+ if (0 == ep) {
-+ DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
-+ return 0;
-+ }
-+ usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
-+ if (0 == usb_req) {
-+ DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
-+ return 0;
-+ }
-+ memset(usb_req, 0, sizeof(*usb_req));
-+ usb_req->dma = DWC_DMA_ADDR_INVALID;
-+
-+ return usb_req;
-+}
-+
-+/**
-+ * This function frees a request object.
-+ *
-+ * @param ep The endpoint associated with the request
-+ * @param req The request being freed
-+ */
-+static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
-+{
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
-+
-+ if (0 == ep || 0 == req) {
-+ DWC_WARN("%s() %s\n", __func__,
-+ "Invalid ep or req argument!\n");
-+ return;
-+ }
-+
-+ kfree(req);
-+}
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+/**
-+ * This function allocates an I/O buffer to be used for a transfer
-+ * to/from the specified endpoint.
-+ *
-+ * @param usb_ep The endpoint to be used with with the request
-+ * @param bytes The desired number of bytes for the buffer
-+ * @param dma Pointer to the buffer's DMA address; must be valid
-+ * @param gfp_flags the GFP_* flags to use.
-+ * @return address of a new buffer or null is buffer could not be allocated.
-+ */
-+static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
-+ dma_addr_t * dma, gfp_t gfp_flags)
-+{
-+ void *buf;
-+ dwc_otg_pcd_t *pcd = 0;
-+
-+ pcd = gadget_wrapper->pcd;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
-+ dma, gfp_flags);
-+
-+ /* Check dword alignment */
-+ if ((bytes & 0x3UL) != 0) {
-+ DWC_WARN("%s() Buffer size is not a multiple of"
-+ "DWORD size (%d)", __func__, bytes);
-+ }
-+
-+ buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
-+
-+ /* Check dword alignment */
-+ if (((int)buf & 0x3UL) != 0) {
-+ DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
-+ __func__, buf);
-+ }
-+
-+ return buf;
-+}
-+
-+/**
-+ * This function frees an I/O buffer that was allocated by alloc_buffer.
-+ *
-+ * @param usb_ep the endpoint associated with the buffer
-+ * @param buf address of the buffer
-+ * @param dma The buffer's DMA address
-+ * @param bytes The number of bytes of the buffer
-+ */
-+static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
-+ dma_addr_t dma, unsigned bytes)
-+{
-+ dwc_otg_pcd_t *pcd = 0;
-+
-+ pcd = gadget_wrapper->pcd;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
-+
-+ dma_free_coherent(NULL, bytes, buf, dma);
-+}
-+#endif
-+
-+/**
-+ * This function is used to submit an I/O Request to an EP.
-+ *
-+ * - When the request completes the request's completion callback
-+ * is called to return the request to the driver.
-+ * - An EP, except control EPs, may have multiple requests
-+ * pending.
-+ * - Once submitted the request cannot be examined or modified.
-+ * - Each request is turned into one or more packets.
-+ * - A BULK EP can queue any amount of data; the transfer is
-+ * packetized.
-+ * - Zero length Packets are specified with the request 'zero'
-+ * flag.
-+ */
-+static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
-+ gfp_t gfp_flags)
-+{
-+ dwc_otg_pcd_t *pcd;
-+ struct dwc_otg_pcd_ep *ep = NULL;
-+ int retval = 0, is_isoc_ep = 0;
-+ dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
-+ __func__, usb_ep, usb_req, gfp_flags);
-+
-+ if (!usb_req || !usb_req->complete || !usb_req->buf) {
-+ DWC_WARN("bad params\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!usb_ep) {
-+ DWC_WARN("bad ep\n");
-+ return -EINVAL;
-+ }
-+
-+ pcd = gadget_wrapper->pcd;
-+ if (!gadget_wrapper->driver ||
-+ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
-+ DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
-+ gadget_wrapper->gadget.speed);
-+ DWC_WARN("bogus device state\n");
-+ return -ESHUTDOWN;
-+ }
-+
-+ DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
-+ usb_ep->name, usb_req, usb_req->length, usb_req->buf);
-+
-+ usb_req->status = -EINPROGRESS;
-+ usb_req->actual = 0;
-+
-+ ep = ep_from_handle(pcd, usb_ep);
-+ if (ep == NULL)
-+ is_isoc_ep = 0;
-+ else
-+ is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ dma_addr = usb_req->dma;
-+#else
-+ if (GET_CORE_IF(pcd)->dma_enable) {
-+ dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
-+ struct device *dev = NULL;
-+
-+ if (otg_dev != NULL)
-+ dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
-+
-+ if (usb_req->length != 0 &&
-+ usb_req->dma == DWC_DMA_ADDR_INVALID) {
-+ dma_addr = dma_map_single(dev, usb_req->buf,
-+ usb_req->length,
-+ ep->dwc_ep.is_in ?
-+ DMA_TO_DEVICE:
-+ DMA_FROM_DEVICE);
-+ }
-+ }
-+#endif
-+
-+#ifdef DWC_UTE_PER_IO
-+ if (is_isoc_ep == 1) {
-+ retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
-+ usb_req->length, usb_req->zero, usb_req,
-+ gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
-+ if (retval)
-+ return -EINVAL;
-+
-+ return 0;
-+ }
-+#endif
-+ retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
-+ usb_req->length, usb_req->zero, usb_req,
-+ gfp_flags == GFP_ATOMIC ? 1 : 0);
-+ if (retval) {
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * This function cancels an I/O request from an EP.
-+ */
-+static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
-+{
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
-+
-+ if (!usb_ep || !usb_req) {
-+ DWC_WARN("bad argument\n");
-+ return -EINVAL;
-+ }
-+ if (!gadget_wrapper->driver ||
-+ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
-+ DWC_WARN("bogus device state\n");
-+ return -ESHUTDOWN;
-+ }
-+ if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * usb_ep_set_halt stalls an endpoint.
-+ *
-+ * usb_ep_clear_halt clears an endpoint halt and resets its data
-+ * toggle.
-+ *
-+ * Both of these functions are implemented with the same underlying
-+ * function. The behavior depends on the value argument.
-+ *
-+ * @param[in] usb_ep the Endpoint to halt or clear halt.
-+ * @param[in] value
-+ * - 0 means clear_halt.
-+ * - 1 means set_halt,
-+ * - 2 means clear stall lock flag.
-+ * - 3 means set stall lock flag.
-+ */
-+static int ep_halt(struct usb_ep *usb_ep, int value)
-+{
-+ int retval = 0;
-+
-+ DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
-+
-+ if (!usb_ep) {
-+ DWC_WARN("bad ep\n");
-+ return -EINVAL;
-+ }
-+
-+ retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
-+ if (retval == -DWC_E_AGAIN) {
-+ return -EAGAIN;
-+ } else if (retval) {
-+ retval = -EINVAL;
-+ }
-+
-+ return retval;
-+}
-+
-+//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
-+#if 0
-+/**
-+ * ep_wedge: sets the halt feature and ignores clear requests
-+ *
-+ * @usb_ep: the endpoint being wedged
-+ *
-+ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
-+ * requests. If the gadget driver clears the halt status, it will
-+ * automatically unwedge the endpoint.
-+ *
-+ * Returns zero on success, else negative errno. *
-+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
-+ */
-+static int ep_wedge(struct usb_ep *usb_ep)
-+{
-+ int retval = 0;
-+
-+ DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
-+
-+ if (!usb_ep) {
-+ DWC_WARN("bad ep\n");
-+ return -EINVAL;
-+ }
-+
-+ retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
-+ if (retval == -DWC_E_AGAIN) {
-+ retval = -EAGAIN;
-+ } else if (retval) {
-+ retval = -EINVAL;
-+ }
-+
-+ return retval;
-+}
-+#endif
-+
-+#ifdef DWC_EN_ISOC
-+/**
-+ * This function is used to submit an ISOC Transfer Request to an EP.
-+ *
-+ * - Every time a sync period completes the request's completion callback
-+ * is called to provide data to the gadget driver.
-+ * - Once submitted the request cannot be modified.
-+ * - Each request is turned into periodic data packets untill ISO
-+ * Transfer is stopped..
-+ */
-+static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
-+ gfp_t gfp_flags)
-+{
-+ int retval = 0;
-+
-+ if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
-+ DWC_WARN("bad params\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!usb_ep) {
-+ DWC_PRINTF("bad params\n");
-+ return -EINVAL;
-+ }
-+
-+ req->status = -EINPROGRESS;
-+
-+ retval =
-+ dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
-+ req->buf1, req->dma0, req->dma1,
-+ req->sync_frame, req->data_pattern_frame,
-+ req->data_per_frame,
-+ req->
-+ flags & USB_REQ_ISO_ASAP ? -1 :
-+ req->start_frame, req->buf_proc_intrvl,
-+ req, gfp_flags == GFP_ATOMIC ? 1 : 0);
-+
-+ if (retval) {
-+ return -EINVAL;
-+ }
-+
-+ return retval;
-+}
-+
-+/**
-+ * This function stops ISO EP Periodic Data Transfer.
-+ */
-+static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
-+{
-+ int retval = 0;
-+ if (!usb_ep) {
-+ DWC_WARN("bad ep\n");
-+ }
-+
-+ if (!gadget_wrapper->driver ||
-+ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
-+ DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
-+ gadget_wrapper->gadget.speed);
-+ DWC_WARN("bogus device state\n");
-+ }
-+
-+ dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
-+ if (retval) {
-+ retval = -EINVAL;
-+ }
-+
-+ return retval;
-+}
-+
-+static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
-+ int packets, gfp_t gfp_flags)
-+{
-+ struct usb_iso_request *pReq = NULL;
-+ uint32_t req_size;
-+
-+ req_size = sizeof(struct usb_iso_request);
-+ req_size +=
-+ (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
-+
-+ pReq = kmalloc(req_size, gfp_flags);
-+ if (!pReq) {
-+ DWC_WARN("Can't allocate Iso Request\n");
-+ return 0;
-+ }
-+ pReq->iso_packet_desc0 = (void *)(pReq + 1);
-+
-+ pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
-+
-+ return pReq;
-+}
-+
-+static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
-+{
-+ kfree(req);
-+}
-+
-+static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
-+ .ep_ops = {
-+ .enable = ep_enable,
-+ .disable = ep_disable,
-+
-+ .alloc_request = dwc_otg_pcd_alloc_request,
-+ .free_request = dwc_otg_pcd_free_request,
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ .alloc_buffer = dwc_otg_pcd_alloc_buffer,
-+ .free_buffer = dwc_otg_pcd_free_buffer,
-+#endif
-+
-+ .queue = ep_queue,
-+ .dequeue = ep_dequeue,
-+
-+ .set_halt = ep_halt,
-+ .fifo_status = 0,
-+ .fifo_flush = 0,
-+ },
-+ .iso_ep_start = iso_ep_start,
-+ .iso_ep_stop = iso_ep_stop,
-+ .alloc_iso_request = alloc_iso_request,
-+ .free_iso_request = free_iso_request,
-+};
-+
-+#else
-+
-+ int (*enable) (struct usb_ep *ep,
-+ const struct usb_endpoint_descriptor *desc);
-+ int (*disable) (struct usb_ep *ep);
-+
-+ struct usb_request *(*alloc_request) (struct usb_ep *ep,
-+ gfp_t gfp_flags);
-+ void (*free_request) (struct usb_ep *ep, struct usb_request *req);
-+
-+ int (*queue) (struct usb_ep *ep, struct usb_request *req,
-+ gfp_t gfp_flags);
-+ int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
-+
-+ int (*set_halt) (struct usb_ep *ep, int value);
-+ int (*set_wedge) (struct usb_ep *ep);
-+
-+ int (*fifo_status) (struct usb_ep *ep);
-+ void (*fifo_flush) (struct usb_ep *ep);
-+static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
-+ .enable = ep_enable,
-+ .disable = ep_disable,
-+
-+ .alloc_request = dwc_otg_pcd_alloc_request,
-+ .free_request = dwc_otg_pcd_free_request,
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+ .alloc_buffer = dwc_otg_pcd_alloc_buffer,
-+ .free_buffer = dwc_otg_pcd_free_buffer,
-+#else
-+ /* .set_wedge = ep_wedge, */
-+ .set_wedge = NULL, /* uses set_halt instead */
-+#endif
-+
-+ .queue = ep_queue,
-+ .dequeue = ep_dequeue,
-+
-+ .set_halt = ep_halt,
-+ .fifo_status = 0,
-+ .fifo_flush = 0,
-+
-+};
-+
-+#endif /* _EN_ISOC_ */
-+/* Gadget Operations */
-+/**
-+ * The following gadget operations will be implemented in the DWC_otg
-+ * PCD. Functions in the API that are not described below are not
-+ * implemented.
-+ *
-+ * The Gadget API provides wrapper functions for each of the function
-+ * pointers defined in usb_gadget_ops. The Gadget Driver calls the
-+ * wrapper function, which then calls the underlying PCD function. The
-+ * following sections are named according to the wrapper functions
-+ * (except for ioctl, which doesn't have a wrapper function). Within
-+ * each section, the corresponding DWC_otg PCD function name is
-+ * specified.
-+ *
-+ */
-+
-+/**
-+ *Gets the USB Frame number of the last SOF.
-+ */
-+static int get_frame_number(struct usb_gadget *gadget)
-+{
-+ struct gadget_wrapper *d;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
-+
-+ if (gadget == 0) {
-+ return -ENODEV;
-+ }
-+
-+ d = container_of(gadget, struct gadget_wrapper, gadget);
-+ return dwc_otg_pcd_get_frame_number(d->pcd);
-+}
-+
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+static int test_lpm_enabled(struct usb_gadget *gadget)
-+{
-+ struct gadget_wrapper *d;
-+
-+ d = container_of(gadget, struct gadget_wrapper, gadget);
-+
-+ return dwc_otg_pcd_is_lpm_enabled(d->pcd);
-+}
-+#endif
-+
-+/**
-+ * Initiates Session Request Protocol (SRP) to wakeup the host if no
-+ * session is in progress. If a session is already in progress, but
-+ * the device is suspended, remote wakeup signaling is started.
-+ *
-+ */
-+static int wakeup(struct usb_gadget *gadget)
-+{
-+ struct gadget_wrapper *d;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
-+
-+ if (gadget == 0) {
-+ return -ENODEV;
-+ } else {
-+ d = container_of(gadget, struct gadget_wrapper, gadget);
-+ }
-+ dwc_otg_pcd_wakeup(d->pcd);
-+ return 0;
-+}
-+
-+static const struct usb_gadget_ops dwc_otg_pcd_ops = {
-+ .get_frame = get_frame_number,
-+ .wakeup = wakeup,
-+#ifdef CONFIG_USB_DWC_OTG_LPM
-+ .lpm_support = test_lpm_enabled,
-+#endif
-+ // current versions must always be self-powered
-+};
-+
-+static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
-+{
-+ int retval = -DWC_E_NOT_SUPPORTED;
-+ if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
-+ retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
-+ (struct usb_ctrlrequest
-+ *)bytes);
-+ }
-+
-+ if (retval == -ENOTSUPP) {
-+ retval = -DWC_E_NOT_SUPPORTED;
-+ } else if (retval < 0) {
-+ retval = -DWC_E_INVALID;
-+ }
-+
-+ return retval;
-+}
-+
-+#ifdef DWC_EN_ISOC
-+static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle, int proc_buf_num)
-+{
-+ int i, packet_count;
-+ struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
-+ struct usb_iso_request *iso_req = req_handle;
-+
-+ if (proc_buf_num) {
-+ iso_packet = iso_req->iso_packet_desc1;
-+ } else {
-+ iso_packet = iso_req->iso_packet_desc0;
-+ }
-+ packet_count =
-+ dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
-+ for (i = 0; i < packet_count; ++i) {
-+ int status;
-+ int actual;
-+ int offset;
-+ dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
-+ i, &status, &actual, &offset);
-+ switch (status) {
-+ case -DWC_E_NO_DATA:
-+ status = -ENODATA;
-+ break;
-+ default:
-+ if (status) {
-+ DWC_PRINTF("unknown status in isoc packet\n");
-+ }
-+
-+ }
-+ iso_packet[i].status = status;
-+ iso_packet[i].offset = offset;
-+ iso_packet[i].actual_length = actual;
-+ }
-+
-+ iso_req->status = 0;
-+ iso_req->process_buffer(ep_handle, iso_req);
-+
-+ return 0;
-+}
-+#endif /* DWC_EN_ISOC */
-+
-+#ifdef DWC_UTE_PER_IO
-+/**
-+ * Copy the contents of the extended request to the Linux usb_request's
-+ * extended part and call the gadget's completion.
-+ *
-+ * @param pcd Pointer to the pcd structure
-+ * @param ep_handle Void pointer to the usb_ep structure
-+ * @param req_handle Void pointer to the usb_request structure
-+ * @param status Request status returned from the portable logic
-+ * @param ereq_port Void pointer to the extended request structure
-+ * created in the the portable part that contains the
-+ * results of the processed iso packets.
-+ */
-+static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle, int32_t status, void *ereq_port)
-+{
-+ struct dwc_ute_iso_req_ext *ereqorg = NULL;
-+ struct dwc_iso_xreq_port *ereqport = NULL;
-+ struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
-+ int i;
-+ struct usb_request *req;
-+ //struct dwc_ute_iso_packet_descriptor *
-+ //int status = 0;
-+
-+ req = (struct usb_request *)req_handle;
-+ ereqorg = &req->ext_req;
-+ ereqport = (struct dwc_iso_xreq_port *)ereq_port;
-+ desc_org = ereqorg->per_io_frame_descs;
-+
-+ if (req && req->complete) {
-+ /* Copy the request data from the portable logic to our request */
-+ for (i = 0; i < ereqport->pio_pkt_count; i++) {
-+ desc_org[i].actual_length =
-+ ereqport->per_io_frame_descs[i].actual_length;
-+ desc_org[i].status =
-+ ereqport->per_io_frame_descs[i].status;
-+ }
-+
-+ switch (status) {
-+ case -DWC_E_SHUTDOWN:
-+ req->status = -ESHUTDOWN;
-+ break;
-+ case -DWC_E_RESTART:
-+ req->status = -ECONNRESET;
-+ break;
-+ case -DWC_E_INVALID:
-+ req->status = -EINVAL;
-+ break;
-+ case -DWC_E_TIMEOUT:
-+ req->status = -ETIMEDOUT;
-+ break;
-+ default:
-+ req->status = status;
-+ }
-+
-+ /* And call the gadget's completion */
-+ req->complete(ep_handle, req);
-+ }
-+
-+ return 0;
-+}
-+#endif /* DWC_UTE_PER_IO */
-+
-+static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
-+ void *req_handle, int32_t status, uint32_t actual)
-+{
-+ struct usb_request *req = (struct usb_request *)req_handle;
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
-+ struct dwc_otg_pcd_ep *ep = NULL;
-+#endif
-+
-+ if (req && req->complete) {
-+ switch (status) {
-+ case -DWC_E_SHUTDOWN:
-+ req->status = -ESHUTDOWN;
-+ break;
-+ case -DWC_E_RESTART:
-+ req->status = -ECONNRESET;
-+ break;
-+ case -DWC_E_INVALID:
-+ req->status = -EINVAL;
-+ break;
-+ case -DWC_E_TIMEOUT:
-+ req->status = -ETIMEDOUT;
-+ break;
-+ default:
-+ req->status = status;
-+
-+ }
-+
-+ req->actual = actual;
-+ DWC_SPINUNLOCK(pcd->lock);
-+ req->complete(ep_handle, req);
-+ DWC_SPINLOCK(pcd->lock);
-+ }
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
-+ ep = ep_from_handle(pcd, ep_handle);
-+ if (GET_CORE_IF(pcd)->dma_enable) {
-+ if (req->length != 0) {
-+ dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
-+ struct device *dev = NULL;
-+
-+ if (otg_dev != NULL)
-+ dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
-+
-+ dma_unmap_single(dev, req->dma, req->length,
-+ ep->dwc_ep.is_in ?
-+ DMA_TO_DEVICE: DMA_FROM_DEVICE);
-+ }
-+ }
-+#endif
-+
-+ return 0;
-+}
-+
-+static int _connect(dwc_otg_pcd_t * pcd, int speed)
-+{
-+ gadget_wrapper->gadget.speed = speed;
-+ return 0;
-+}
-+
-+static int _disconnect(dwc_otg_pcd_t * pcd)
-+{
-+ if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
-+ gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
-+ }
-+ return 0;
-+}
-+
-+static int _resume(dwc_otg_pcd_t * pcd)
-+{
-+ if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
-+ gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
-+ }
-+
-+ return 0;
-+}
-+
-+static int _suspend(dwc_otg_pcd_t * pcd)
-+{
-+ if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
-+ gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * This function updates the otg values in the gadget structure.
-+ */
-+static int _hnp_changed(dwc_otg_pcd_t * pcd)
-+{
-+
-+ if (!gadget_wrapper->gadget.is_otg)
-+ return 0;
-+
-+ gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
-+ gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
-+ gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
-+ return 0;
-+}
-+
-+static int _reset(dwc_otg_pcd_t * pcd)
-+{
-+ return 0;
-+}
-+
-+#ifdef DWC_UTE_CFI
-+static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
-+{
-+ int retval = -DWC_E_INVALID;
-+ if (gadget_wrapper->driver->cfi_feature_setup) {
-+ retval =
-+ gadget_wrapper->driver->
-+ cfi_feature_setup(&gadget_wrapper->gadget,
-+ (struct cfi_usb_ctrlrequest *)cfi_req);
-+ }
-+
-+ return retval;
-+}
-+#endif
-+
-+static const struct dwc_otg_pcd_function_ops fops = {
-+ .complete = _complete,
-+#ifdef DWC_EN_ISOC
-+ .isoc_complete = _isoc_complete,
-+#endif
-+ .setup = _setup,
-+ .disconnect = _disconnect,
-+ .connect = _connect,
-+ .resume = _resume,
-+ .suspend = _suspend,
-+ .hnp_changed = _hnp_changed,
-+ .reset = _reset,
-+#ifdef DWC_UTE_CFI
-+ .cfi_setup = _cfi_setup,
-+#endif
-+#ifdef DWC_UTE_PER_IO
-+ .xisoc_complete = _xisoc_complete,
-+#endif
-+};
-+
-+/**
-+ * This function is the top level PCD interrupt handler.
-+ */
-+static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
-+{
-+ dwc_otg_pcd_t *pcd = dev;
-+ int32_t retval = IRQ_NONE;
-+
-+ retval = dwc_otg_pcd_handle_intr(pcd);
-+ if (retval != 0) {
-+ S3C2410X_CLEAR_EINTPEND();
-+ }
-+ return IRQ_RETVAL(retval);
-+}
-+
-+/**
-+ * This function initialized the usb_ep structures to there default
-+ * state.
-+ *
-+ * @param d Pointer on gadget_wrapper.
-+ */
-+void gadget_add_eps(struct gadget_wrapper *d)
-+{
-+ static const char *names[] = {
-+
-+ "ep0",
-+ "ep1in",
-+ "ep2in",
-+ "ep3in",
-+ "ep4in",
-+ "ep5in",
-+ "ep6in",
-+ "ep7in",
-+ "ep8in",
-+ "ep9in",
-+ "ep10in",
-+ "ep11in",
-+ "ep12in",
-+ "ep13in",
-+ "ep14in",
-+ "ep15in",
-+ "ep1out",
-+ "ep2out",
-+ "ep3out",
-+ "ep4out",
-+ "ep5out",
-+ "ep6out",
-+ "ep7out",
-+ "ep8out",
-+ "ep9out",
-+ "ep10out",
-+ "ep11out",
-+ "ep12out",
-+ "ep13out",
-+ "ep14out",
-+ "ep15out"
-+ };
-+
-+ int i;
-+ struct usb_ep *ep;
-+ int8_t dev_endpoints;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
-+
-+ INIT_LIST_HEAD(&d->gadget.ep_list);
-+ d->gadget.ep0 = &d->ep0;
-+ d->gadget.speed = USB_SPEED_UNKNOWN;
-+
-+ INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
-+
-+ /**
-+ * Initialize the EP0 structure.
-+ */
-+ ep = &d->ep0;
-+
-+ /* Init the usb_ep structure. */
-+ ep->name = names[0];
-+ ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
-+
-+ /**
-+ * @todo NGS: What should the max packet size be set to
-+ * here? Before EP type is set?
-+ */
-+ ep->maxpacket = MAX_PACKET_SIZE;
-+ dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
-+
-+ list_add_tail(&ep->ep_list, &d->gadget.ep_list);
-+
-+ /**
-+ * Initialize the EP structures.
-+ */
-+ dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
-+
-+ for (i = 0; i < dev_endpoints; i++) {
-+ ep = &d->in_ep[i];
-+
-+ /* Init the usb_ep structure. */
-+ ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
-+ ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
-+
-+ /**
-+ * @todo NGS: What should the max packet size be set to
-+ * here? Before EP type is set?
-+ */
-+ ep->maxpacket = MAX_PACKET_SIZE;
-+ list_add_tail(&ep->ep_list, &d->gadget.ep_list);
-+ }
-+
-+ dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
-+
-+ for (i = 0; i < dev_endpoints; i++) {
-+ ep = &d->out_ep[i];
-+
-+ /* Init the usb_ep structure. */
-+ ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
-+ ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
-+
-+ /**
-+ * @todo NGS: What should the max packet size be set to
-+ * here? Before EP type is set?
-+ */
-+ ep->maxpacket = MAX_PACKET_SIZE;
-+
-+ list_add_tail(&ep->ep_list, &d->gadget.ep_list);
-+ }
-+
-+ /* remove ep0 from the list. There is a ep0 pointer. */
-+ list_del_init(&d->ep0.ep_list);
-+
-+ d->ep0.maxpacket = MAX_EP0_SIZE;
-+}
-+
-+/**
-+ * This function releases the Gadget device.
-+ * required by device_unregister().
-+ *
-+ * @todo Should this do something? Should it free the PCD?
-+ */
-+static void dwc_otg_pcd_gadget_release(struct device *dev)
-+{
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
-+}
-+
-+static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
-+{
-+ static char pcd_name[] = "dwc_otg_pcd";
-+ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
-+ struct gadget_wrapper *d;
-+ int retval;
-+
-+ d = DWC_ALLOC(sizeof(*d));
-+ if (d == NULL) {
-+ return NULL;
-+ }
-+
-+ memset(d, 0, sizeof(*d));
-+
-+ d->gadget.name = pcd_name;
-+ d->pcd = otg_dev->pcd;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-+ strcpy(d->gadget.dev.bus_id, "gadget");
-+#else
-+ dev_set_name(&d->gadget.dev, "%s", "gadget");
-+#endif
-+
-+ d->gadget.dev.parent = &_dev->dev;
-+ d->gadget.dev.release = dwc_otg_pcd_gadget_release;
-+ d->gadget.ops = &dwc_otg_pcd_ops;
-+ d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
-+ d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
-+
-+ d->driver = 0;
-+ /* Register the gadget device */
-+ retval = device_register(&d->gadget.dev);
-+ if (retval != 0) {
-+ DWC_ERROR("device_register failed\n");
-+ DWC_FREE(d);
-+ return NULL;
-+ }
-+
-+ return d;
-+}
-+
-+static void free_wrapper(struct gadget_wrapper *d)
-+{
-+ if (d->driver) {
-+ /* should have been done already by driver model core */
-+ DWC_WARN("driver '%s' is still registered\n",
-+ d->driver->driver.name);
-+ usb_gadget_unregister_driver(d->driver);
-+ }
-+
-+ device_unregister(&d->gadget.dev);
-+ DWC_FREE(d);
-+}
-+
-+/**
-+ * This function initialized the PCD portion of the driver.
-+ *
-+ */
-+int pcd_init(dwc_bus_dev_t *_dev)
-+{
-+ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
-+ int retval = 0;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
-+
-+ otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
-+
-+ if (!otg_dev->pcd) {
-+ DWC_ERROR("dwc_otg_pcd_init failed\n");
-+ return -ENOMEM;
-+ }
-+
-+ otg_dev->pcd->otg_dev = otg_dev;
-+ gadget_wrapper = alloc_wrapper(_dev);
-+
-+ /*
-+ * Initialize EP structures
-+ */
-+ gadget_add_eps(gadget_wrapper);
-+ /*
-+ * Setup interupt handler
-+ */
-+#ifdef PLATFORM_INTERFACE
-+ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
-+ platform_get_irq(_dev, 0));
-+ retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq,
-+ IRQF_SHARED, gadget_wrapper->gadget.name,
-+ otg_dev->pcd);
-+ if (retval != 0) {
-+ DWC_ERROR("request of irq%d failed\n",
-+ platform_get_irq(_dev, 0));
-+ free_wrapper(gadget_wrapper);
-+ return -EBUSY;
-+ }
-+#else
-+ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
-+ _dev->irq);
-+ retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
-+ IRQF_SHARED | IRQF_DISABLED,
-+ gadget_wrapper->gadget.name, otg_dev->pcd);
-+ if (retval != 0) {
-+ DWC_ERROR("request of irq%d failed\n", _dev->irq);
-+ free_wrapper(gadget_wrapper);
-+ return -EBUSY;
-+ }
-+#endif
-+
-+ dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
-+
-+ return retval;
-+}
-+
-+/**
-+ * Cleanup the PCD.
-+ */
-+void pcd_remove(dwc_bus_dev_t *_dev)
-+{
-+ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
-+ dwc_otg_pcd_t *pcd = otg_dev->pcd;
-+
-+ DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
-+
-+ /*
-+ * Free the IRQ
-+ */
-+#ifdef PLATFORM_INTERFACE
-+ free_irq(platform_get_irq(_dev, 0), pcd);
-+#else
-+ free_irq(_dev->irq, pcd);
-+#endif
-+ dwc_otg_pcd_remove(otg_dev->pcd);
-+ free_wrapper(gadget_wrapper);
-+ otg_dev->pcd = 0;
-+}
-+
-+/**
-+ * This function registers a gadget driver with the PCD.
-+ *
-+ * When a driver is successfully registered, it will receive control
-+ * requests including set_configuration(), which enables non-control
-+ * requests. then usb traffic follows until a disconnect is reported.
-+ * then a host may connect again, or the driver might get unbound.
-+ *
-+ * @param driver The driver being registered
-+ * @param bind The bind function of gadget driver
-+ */
-+
-+int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
-+{
-+ int retval;
-+
-+ DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
-+ driver->driver.name);
-+
-+ if (!driver || driver->max_speed == USB_SPEED_UNKNOWN ||
-+ !driver->bind ||
-+ !driver->unbind || !driver->disconnect || !driver->setup) {
-+ DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
-+ return -EINVAL;
-+ }
-+ if (gadget_wrapper == 0) {
-+ DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
-+ return -ENODEV;
-+ }
-+ if (gadget_wrapper->driver != 0) {
-+ DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
-+ return -EBUSY;
-+ }
-+
-+ /* hook up the driver */
-+ gadget_wrapper->driver = driver;
-+ gadget_wrapper->gadget.dev.driver = &driver->driver;
-+
-+ DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
-+ retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver);
-+ if (retval) {
-+ DWC_ERROR("bind to driver %s --> error %d\n",
-+ driver->driver.name, retval);
-+ gadget_wrapper->driver = 0;
-+ gadget_wrapper->gadget.dev.driver = 0;
-+ return retval;
-+ }
-+ DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
-+ driver->driver.name);
-+ return 0;
-+}
-+EXPORT_SYMBOL(usb_gadget_probe_driver);
-+
-+/**
-+ * This function unregisters a gadget driver
-+ *
-+ * @param driver The driver being unregistered
-+ */
-+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
-+{
-+ //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
-+
-+ if (gadget_wrapper == 0) {
-+ DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
-+ -ENODEV);
-+ return -ENODEV;
-+ }
-+ if (driver == 0 || driver != gadget_wrapper->driver) {
-+ DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
-+ -EINVAL);
-+ return -EINVAL;
-+ }
-+
-+ driver->unbind(&gadget_wrapper->gadget);
-+ gadget_wrapper->driver = 0;
-+
-+ DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(usb_gadget_unregister_driver);
-+
-+#endif /* DWC_HOST_ONLY */
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_regs.h linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_regs.h
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/dwc_otg_regs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/dwc_otg_regs.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,2550 @@
-+/* ==========================================================================
-+ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
-+ * $Revision: #98 $
-+ * $Date: 2012/08/10 $
-+ * $Change: 2047372 $
-+ *
-+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
-+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
-+ * otherwise expressly agreed to in writing between Synopsys and you.
-+ *
-+ * The Software IS NOT an item of Licensed Software or Licensed Product under
-+ * any End User Software License Agreement or Agreement for Licensed Product
-+ * with Synopsys or any supplement thereto. You are permitted to use and
-+ * redistribute this Software in source and binary forms, with or without
-+ * modification, provided that redistributions of source code must retain this
-+ * notice. You may not view, use, disclose, copy or distribute this file or
-+ * any information contained herein except pursuant to this license grant from
-+ * Synopsys. If you do not agree with this notice, including the disclaimer
-+ * below, then you are not authorized to use the Software.
-+ *
-+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
-+ * ========================================================================== */
-+
-+#ifndef __DWC_OTG_REGS_H__
-+#define __DWC_OTG_REGS_H__
-+
-+#include "dwc_otg_core_if.h"
-+
-+/**
-+ * @file
-+ *
-+ * This file contains the data structures for accessing the DWC_otg core registers.
-+ *
-+ * The application interfaces with the HS OTG core by reading from and
-+ * writing to the Control and Status Register (CSR) space through the
-+ * AHB Slave interface. These registers are 32 bits wide, and the
-+ * addresses are 32-bit-block aligned.
-+ * CSRs are classified as follows:
-+ * - Core Global Registers
-+ * - Device Mode Registers
-+ * - Device Global Registers
-+ * - Device Endpoint Specific Registers
-+ * - Host Mode Registers
-+ * - Host Global Registers
-+ * - Host Port CSRs
-+ * - Host Channel Specific Registers
-+ *
-+ * Only the Core Global registers can be accessed in both Device and
-+ * Host modes. When the HS OTG core is operating in one mode, either
-+ * Device or Host, the application must not access registers from the
-+ * other mode. When the core switches from one mode to another, the
-+ * registers in the new mode of operation must be reprogrammed as they
-+ * would be after a power-on reset.
-+ */
-+
-+/****************************************************************************/
-+/** DWC_otg Core registers .
-+ * The dwc_otg_core_global_regs structure defines the size
-+ * and relative field offsets for the Core Global registers.
-+ */
-+typedef struct dwc_otg_core_global_regs {
-+ /** OTG Control and Status Register. <i>Offset: 000h</i> */
-+ volatile uint32_t gotgctl;
-+ /** OTG Interrupt Register. <i>Offset: 004h</i> */
-+ volatile uint32_t gotgint;
-+ /**Core AHB Configuration Register. <i>Offset: 008h</i> */
-+ volatile uint32_t gahbcfg;
-+
-+#define DWC_GLBINTRMASK 0x0001
-+#define DWC_DMAENABLE 0x0020
-+#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
-+#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
-+#define DWC_PTXEMPTYLVL_EMPTY 0x0100
-+#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
-+
-+ /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
-+ volatile uint32_t gusbcfg;
-+ /**Core Reset Register. <i>Offset: 010h</i> */
-+ volatile uint32_t grstctl;
-+ /**Core Interrupt Register. <i>Offset: 014h</i> */
-+ volatile uint32_t gintsts;
-+ /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
-+ volatile uint32_t gintmsk;
-+ /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
-+ volatile uint32_t grxstsr;
-+ /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
-+ volatile uint32_t grxstsp;
-+ /**Receive FIFO Size Register. <i>Offset: 024h</i> */
-+ volatile uint32_t grxfsiz;
-+ /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
-+ volatile uint32_t gnptxfsiz;
-+ /**Non Periodic Transmit FIFO/Queue Status Register (Read
-+ * Only). <i>Offset: 02Ch</i> */
-+ volatile uint32_t gnptxsts;
-+ /**I2C Access Register. <i>Offset: 030h</i> */
-+ volatile uint32_t gi2cctl;
-+ /**PHY Vendor Control Register. <i>Offset: 034h</i> */
-+ volatile uint32_t gpvndctl;
-+ /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
-+ volatile uint32_t ggpio;
-+ /**User ID Register. <i>Offset: 03Ch</i> */
-+ volatile uint32_t guid;
-+ /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
-+ volatile uint32_t gsnpsid;
-+ /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
-+ volatile uint32_t ghwcfg1;
-+ /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
-+ volatile uint32_t ghwcfg2;
-+#define DWC_SLAVE_ONLY_ARCH 0
-+#define DWC_EXT_DMA_ARCH 1
-+#define DWC_INT_DMA_ARCH 2
-+
-+#define DWC_MODE_HNP_SRP_CAPABLE 0
-+#define DWC_MODE_SRP_ONLY_CAPABLE 1
-+#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
-+#define DWC_MODE_SRP_CAPABLE_DEVICE 3
-+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
-+#define DWC_MODE_SRP_CAPABLE_HOST 5
-+#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
-+
-+ /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
-+ volatile uint32_t ghwcfg3;
-+ /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
-+ volatile uint32_t ghwcfg4;
-+ /** Core LPM Configuration register <i>Offset: 054h</i>*/
-+ volatile uint32_t glpmcfg;
-+ /** Global PowerDn Register <i>Offset: 058h</i> */
-+ volatile uint32_t gpwrdn;
-+ /** Global DFIFO SW Config Register <i>Offset: 05Ch</i> */
-+ volatile uint32_t gdfifocfg;
-+ /** ADP Control Register <i>Offset: 060h</i> */
-+ volatile uint32_t adpctl;
-+ /** Reserved <i>Offset: 064h-0FFh</i> */
-+ volatile uint32_t reserved39[39];
-+ /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
-+ volatile uint32_t hptxfsiz;
-+ /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
-+ otherwise Device Transmit FIFO#n Register.
-+ * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
-+ volatile uint32_t dtxfsiz[15];
-+} dwc_otg_core_global_regs_t;
-+
-+/**
-+ * This union represents the bit fields of the Core OTG Control
-+ * and Status Register (GOTGCTL). Set the bits using the bit
-+ * fields then write the <i>d32</i> value to the register.
-+ */
-+typedef union gotgctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned sesreqscs:1;
-+ unsigned sesreq:1;
-+ unsigned vbvalidoven:1;
-+ unsigned vbvalidovval:1;
-+ unsigned avalidoven:1;
-+ unsigned avalidovval:1;
-+ unsigned bvalidoven:1;
-+ unsigned bvalidovval:1;
-+ unsigned hstnegscs:1;
-+ unsigned hnpreq:1;
-+ unsigned hstsethnpen:1;
-+ unsigned devhnpen:1;
-+ unsigned reserved12_15:4;
-+ unsigned conidsts:1;
-+ unsigned dbnctime:1;
-+ unsigned asesvld:1;
-+ unsigned bsesvld:1;
-+ unsigned otgver:1;
-+ unsigned reserved1:1;
-+ unsigned multvalidbc:5;
-+ unsigned chirpen:1;
-+ unsigned reserved28_31:4;
-+ } b;
-+} gotgctl_data_t;
-+
-+/**
-+ * This union represents the bit fields of the Core OTG Interrupt Register
-+ * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
-+ * value to the register.
-+ */
-+typedef union gotgint_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Current Mode */
-+ unsigned reserved0_1:2;
-+
-+ /** Session End Detected */
-+ unsigned sesenddet:1;
-+
-+ unsigned reserved3_7:5;
-+
-+ /** Session Request Success Status Change */
-+ unsigned sesreqsucstschng:1;
-+ /** Host Negotiation Success Status Change */
-+ unsigned hstnegsucstschng:1;
-+
-+ unsigned reserved10_16:7;
-+
-+ /** Host Negotiation Detected */
-+ unsigned hstnegdet:1;
-+ /** A-Device Timeout Change */
-+ unsigned adevtoutchng:1;
-+ /** Debounce Done */
-+ unsigned debdone:1;
-+ /** Multi-Valued input changed */
-+ unsigned mvic:1;
-+
-+ unsigned reserved31_21:11;
-+
-+ } b;
-+} gotgint_data_t;
-+
-+/**
-+ * This union represents the bit fields of the Core AHB Configuration
-+ * Register (GAHBCFG). Set/clear the bits using the bit fields then
-+ * write the <i>d32</i> value to the register.
-+ */
-+typedef union gahbcfg_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned glblintrmsk:1;
-+#define DWC_GAHBCFG_GLBINT_ENABLE 1
-+
-+ unsigned hburstlen:4;
-+#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
-+#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
-+#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
-+#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
-+#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
-+
-+ unsigned dmaenable:1;
-+#define DWC_GAHBCFG_DMAENABLE 1
-+ unsigned reserved:1;
-+ unsigned nptxfemplvl_txfemplvl:1;
-+ unsigned ptxfemplvl:1;
-+#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
-+#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
-+ unsigned reserved9_20:12;
-+ unsigned remmemsupp:1;
-+ unsigned notialldmawrit:1;
-+ unsigned ahbsingle:1;
-+ unsigned reserved24_31:8;
-+ } b;
-+} gahbcfg_data_t;
-+
-+/**
-+ * This union represents the bit fields of the Core USB Configuration
-+ * Register (GUSBCFG). Set the bits using the bit fields then write
-+ * the <i>d32</i> value to the register.
-+ */
-+typedef union gusbcfg_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned toutcal:3;
-+ unsigned phyif:1;
-+ unsigned ulpi_utmi_sel:1;
-+ unsigned fsintf:1;
-+ unsigned physel:1;
-+ unsigned ddrsel:1;
-+ unsigned srpcap:1;
-+ unsigned hnpcap:1;
-+ unsigned usbtrdtim:4;
-+ unsigned reserved1:1;
-+ unsigned phylpwrclksel:1;
-+ unsigned otgutmifssel:1;
-+ unsigned ulpi_fsls:1;
-+ unsigned ulpi_auto_res:1;
-+ unsigned ulpi_clk_sus_m:1;
-+ unsigned ulpi_ext_vbus_drv:1;
-+ unsigned ulpi_int_vbus_indicator:1;
-+ unsigned term_sel_dl_pulse:1;
-+ unsigned indicator_complement:1;
-+ unsigned indicator_pass_through:1;
-+ unsigned ulpi_int_prot_dis:1;
-+ unsigned ic_usb_cap:1;
-+ unsigned ic_traffic_pull_remove:1;
-+ unsigned tx_end_delay:1;
-+ unsigned force_host_mode:1;
-+ unsigned force_dev_mode:1;
-+ unsigned reserved31:1;
-+ } b;
-+} gusbcfg_data_t;
-+
-+/**
-+ * This union represents the bit fields of the Core Reset Register
-+ * (GRSTCTL). Set/clear the bits using the bit fields then write the
-+ * <i>d32</i> value to the register.
-+ */
-+typedef union grstctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Core Soft Reset (CSftRst) (Device and Host)
-+ *
-+ * The application can flush the control logic in the
-+ * entire core using this bit. This bit resets the
-+ * pipelines in the AHB Clock domain as well as the
-+ * PHY Clock domain.
-+ *
-+ * The state machines are reset to an IDLE state, the
-+ * control bits in the CSRs are cleared, all the
-+ * transmit FIFOs and the receive FIFO are flushed.
-+ *
-+ * The status mask bits that control the generation of
-+ * the interrupt, are cleared, to clear the
-+ * interrupt. The interrupt status bits are not
-+ * cleared, so the application can get the status of
-+ * any events that occurred in the core after it has
-+ * set this bit.
-+ *
-+ * Any transactions on the AHB are terminated as soon
-+ * as possible following the protocol. Any
-+ * transactions on the USB are terminated immediately.
-+ *
-+ * The configuration settings in the CSRs are
-+ * unchanged, so the software doesn't have to
-+ * reprogram these registers (Device
-+ * Configuration/Host Configuration/Core System
-+ * Configuration/Core PHY Configuration).
-+ *
-+ * The application can write to this bit, any time it
-+ * wants to reset the core. This is a self clearing
-+ * bit and the core clears this bit after all the
-+ * necessary logic is reset in the core, which may
-+ * take several clocks, depending on the current state
-+ * of the core.
-+ */
-+ unsigned csftrst:1;
-+ /** Hclk Soft Reset
-+ *
-+ * The application uses this bit to reset the control logic in
-+ * the AHB clock domain. Only AHB clock domain pipelines are
-+ * reset.
-+ */
-+ unsigned hsftrst:1;
-+ /** Host Frame Counter Reset (Host Only)<br>
-+ *
-+ * The application can reset the (micro)frame number
-+ * counter inside the core, using this bit. When the
-+ * (micro)frame counter is reset, the subsequent SOF
-+ * sent out by the core, will have a (micro)frame
-+ * number of 0.
-+ */
-+ unsigned hstfrm:1;
-+ /** In Token Sequence Learning Queue Flush
-+ * (INTknQFlsh) (Device Only)
-+ */
-+ unsigned intknqflsh:1;
-+ /** RxFIFO Flush (RxFFlsh) (Device and Host)
-+ *
-+ * The application can flush the entire Receive FIFO
-+ * using this bit. The application must first
-+ * ensure that the core is not in the middle of a
-+ * transaction. The application should write into
-+ * this bit, only after making sure that neither the
-+ * DMA engine is reading from the RxFIFO nor the MAC
-+ * is writing the data in to the FIFO. The
-+ * application should wait until the bit is cleared
-+ * before performing any other operations. This bit
-+ * will takes 8 clocks (slowest of PHY or AHB clock)
-+ * to clear.
-+ */
-+ unsigned rxfflsh:1;
-+ /** TxFIFO Flush (TxFFlsh) (Device and Host).
-+ *
-+ * This bit is used to selectively flush a single or
-+ * all transmit FIFOs. The application must first
-+ * ensure that the core is not in the middle of a
-+ * transaction. The application should write into
-+ * this bit, only after making sure that neither the
-+ * DMA engine is writing into the TxFIFO nor the MAC
-+ * is reading the data out of the FIFO. The
-+ * application should wait until the core clears this
-+ * bit, before performing any operations. This bit
-+ * will takes 8 clocks (slowest of PHY or AHB clock)
-+ * to clear.
-+ */
-+ unsigned txfflsh:1;
-+
-+ /** TxFIFO Number (TxFNum) (Device and Host).
-+ *
-+ * This is the FIFO number which needs to be flushed,
-+ * using the TxFIFO Flush bit. This field should not
-+ * be changed until the TxFIFO Flush bit is cleared by
-+ * the core.
-+ * - 0x0 : Non Periodic TxFIFO Flush
-+ * - 0x1 : Periodic TxFIFO #1 Flush in device mode
-+ * or Periodic TxFIFO in host mode
-+ * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
-+ * - ...
-+ * - 0xF : Periodic TxFIFO #15 Flush in device mode
-+ * - 0x10: Flush all the Transmit NonPeriodic and
-+ * Transmit Periodic FIFOs in the core
-+ */
-+ unsigned txfnum:5;
-+ /** Reserved */
-+ unsigned reserved11_29:19;
-+ /** DMA Request Signal. Indicated DMA request is in
-+ * probress. Used for debug purpose. */
-+ unsigned dmareq:1;
-+ /** AHB Master Idle. Indicates the AHB Master State
-+ * Machine is in IDLE condition. */
-+ unsigned ahbidle:1;
-+ } b;
-+} grstctl_t;
-+
-+/**
-+ * This union represents the bit fields of the Core Interrupt Mask
-+ * Register (GINTMSK). Set/clear the bits using the bit fields then
-+ * write the <i>d32</i> value to the register.
-+ */
-+typedef union gintmsk_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned reserved0:1;
-+ unsigned modemismatch:1;
-+ unsigned otgintr:1;
-+ unsigned sofintr:1;
-+ unsigned rxstsqlvl:1;
-+ unsigned nptxfempty:1;
-+ unsigned ginnakeff:1;
-+ unsigned goutnakeff:1;
-+ unsigned ulpickint:1;
-+ unsigned i2cintr:1;
-+ unsigned erlysuspend:1;
-+ unsigned usbsuspend:1;
-+ unsigned usbreset:1;
-+ unsigned enumdone:1;
-+ unsigned isooutdrop:1;
-+ unsigned eopframe:1;
-+ unsigned restoredone:1;
-+ unsigned epmismatch:1;
-+ unsigned inepintr:1;
-+ unsigned outepintr:1;
-+ unsigned incomplisoin:1;
-+ unsigned incomplisoout:1;
-+ unsigned fetsusp:1;
-+ unsigned resetdet:1;
-+ unsigned portintr:1;
-+ unsigned hcintr:1;
-+ unsigned ptxfempty:1;
-+ unsigned lpmtranrcvd:1;
-+ unsigned conidstschng:1;
-+ unsigned disconnect:1;
-+ unsigned sessreqintr:1;
-+ unsigned wkupintr:1;
-+ } b;
-+} gintmsk_data_t;
-+/**
-+ * This union represents the bit fields of the Core Interrupt Register
-+ * (GINTSTS). Set/clear the bits using the bit fields then write the
-+ * <i>d32</i> value to the register.
-+ */
-+typedef union gintsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+#define DWC_SOF_INTR_MASK 0x0008
-+ /** register bits */
-+ struct {
-+#define DWC_HOST_MODE 1
-+ unsigned curmode:1;
-+ unsigned modemismatch:1;
-+ unsigned otgintr:1;
-+ unsigned sofintr:1;
-+ unsigned rxstsqlvl:1;
-+ unsigned nptxfempty:1;
-+ unsigned ginnakeff:1;
-+ unsigned goutnakeff:1;
-+ unsigned ulpickint:1;
-+ unsigned i2cintr:1;
-+ unsigned erlysuspend:1;
-+ unsigned usbsuspend:1;
-+ unsigned usbreset:1;
-+ unsigned enumdone:1;
-+ unsigned isooutdrop:1;
-+ unsigned eopframe:1;
-+ unsigned restoredone:1;
-+ unsigned epmismatch:1;
-+ unsigned inepint:1;
-+ unsigned outepintr:1;
-+ unsigned incomplisoin:1;
-+ unsigned incomplisoout:1;
-+ unsigned fetsusp:1;
-+ unsigned resetdet:1;
-+ unsigned portintr:1;
-+ unsigned hcintr:1;
-+ unsigned ptxfempty:1;
-+ unsigned lpmtranrcvd:1;
-+ unsigned conidstschng:1;
-+ unsigned disconnect:1;
-+ unsigned sessreqintr:1;
-+ unsigned wkupintr:1;
-+ } b;
-+} gintsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device Receive Status Read and
-+ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
-+ * element then read out the bits using the <i>b</i>it elements.
-+ */
-+typedef union device_grxsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned epnum:4;
-+ unsigned bcnt:11;
-+ unsigned dpid:2;
-+
-+#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
-+#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
-+
-+#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
-+#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
-+#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
-+ unsigned pktsts:4;
-+ unsigned fn:4;
-+ unsigned reserved25_31:7;
-+ } b;
-+} device_grxsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Receive Status Read and
-+ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
-+ * element then read out the bits using the <i>b</i>it elements.
-+ */
-+typedef union host_grxsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned chnum:4;
-+ unsigned bcnt:11;
-+ unsigned dpid:2;
-+
-+ unsigned pktsts:4;
-+#define DWC_GRXSTS_PKTSTS_IN 0x2
-+#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
-+#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
-+#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
-+
-+ unsigned reserved21_31:11;
-+ } b;
-+} host_grxsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
-+ * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element
-+ * then read out the bits using the <i>b</i>it elements.
-+ */
-+typedef union fifosize_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned startaddr:16;
-+ unsigned depth:16;
-+ } b;
-+} fifosize_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Non-Periodic Transmit
-+ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
-+ * <i>d32</i> element then read out the bits using the <i>b</i>it
-+ * elements.
-+ */
-+typedef union gnptxsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned nptxfspcavail:16;
-+ unsigned nptxqspcavail:8;
-+ /** Top of the Non-Periodic Transmit Request Queue
-+ * - bit 24 - Terminate (Last entry for the selected
-+ * channel/EP)
-+ * - bits 26:25 - Token Type
-+ * - 2'b00 - IN/OUT
-+ * - 2'b01 - Zero Length OUT
-+ * - 2'b10 - PING/Complete Split
-+ * - 2'b11 - Channel Halt
-+ * - bits 30:27 - Channel/EP Number
-+ */
-+ unsigned nptxqtop_terminate:1;
-+ unsigned nptxqtop_token:2;
-+ unsigned nptxqtop_chnep:4;
-+ unsigned reserved:1;
-+ } b;
-+} gnptxsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Transmit
-+ * FIFO Status Register (DTXFSTS). Read the register into the
-+ * <i>d32</i> element then read out the bits using the <i>b</i>it
-+ * elements.
-+ */
-+typedef union dtxfsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned txfspcavail:16;
-+ unsigned reserved:16;
-+ } b;
-+} dtxfsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the I2C Control Register
-+ * (I2CCTL). Read the register into the <i>d32</i> element then read out the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union gi2cctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned rwdata:8;
-+ unsigned regaddr:8;
-+ unsigned addr:7;
-+ unsigned i2cen:1;
-+ unsigned ack:1;
-+ unsigned i2csuspctl:1;
-+ unsigned i2cdevaddr:2;
-+ unsigned i2cdatse0:1;
-+ unsigned reserved:1;
-+ unsigned rw:1;
-+ unsigned bsydne:1;
-+ } b;
-+} gi2cctl_data_t;
-+
-+/**
-+ * This union represents the bit fields in the PHY Vendor Control Register
-+ * (GPVNDCTL). Read the register into the <i>d32</i> element then read out the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union gpvndctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned regdata:8;
-+ unsigned vctrl:8;
-+ unsigned regaddr16_21:6;
-+ unsigned regwr:1;
-+ unsigned reserved23_24:2;
-+ unsigned newregreq:1;
-+ unsigned vstsbsy:1;
-+ unsigned vstsdone:1;
-+ unsigned reserved28_30:3;
-+ unsigned disulpidrvr:1;
-+ } b;
-+} gpvndctl_data_t;
-+
-+/**
-+ * This union represents the bit fields in the General Purpose
-+ * Input/Output Register (GGPIO).
-+ * Read the register into the <i>d32</i> element then read out the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union ggpio_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned gpi:16;
-+ unsigned gpo:16;
-+ } b;
-+} ggpio_data_t;
-+
-+/**
-+ * This union represents the bit fields in the User ID Register
-+ * (GUID). Read the register into the <i>d32</i> element then read out the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union guid_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned rwdata:32;
-+ } b;
-+} guid_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Synopsys ID Register
-+ * (GSNPSID). Read the register into the <i>d32</i> element then read out the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union gsnpsid_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned rwdata:32;
-+ } b;
-+} gsnpsid_data_t;
-+
-+/**
-+ * This union represents the bit fields in the User HW Config1
-+ * Register. Read the register into the <i>d32</i> element then read
-+ * out the bits using the <i>b</i>it elements.
-+ */
-+typedef union hwcfg1_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned ep_dir0:2;
-+ unsigned ep_dir1:2;
-+ unsigned ep_dir2:2;
-+ unsigned ep_dir3:2;
-+ unsigned ep_dir4:2;
-+ unsigned ep_dir5:2;
-+ unsigned ep_dir6:2;
-+ unsigned ep_dir7:2;
-+ unsigned ep_dir8:2;
-+ unsigned ep_dir9:2;
-+ unsigned ep_dir10:2;
-+ unsigned ep_dir11:2;
-+ unsigned ep_dir12:2;
-+ unsigned ep_dir13:2;
-+ unsigned ep_dir14:2;
-+ unsigned ep_dir15:2;
-+ } b;
-+} hwcfg1_data_t;
-+
-+/**
-+ * This union represents the bit fields in the User HW Config2
-+ * Register. Read the register into the <i>d32</i> element then read
-+ * out the bits using the <i>b</i>it elements.
-+ */
-+typedef union hwcfg2_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /* GHWCFG2 */
-+ unsigned op_mode:3;
-+#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
-+#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
-+#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
-+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
-+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
-+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
-+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
-+
-+ unsigned architecture:2;
-+ unsigned point2point:1;
-+ unsigned hs_phy_type:2;
-+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
-+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
-+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
-+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
-+
-+ unsigned fs_phy_type:2;
-+ unsigned num_dev_ep:4;
-+ unsigned num_host_chan:4;
-+ unsigned perio_ep_supported:1;
-+ unsigned dynamic_fifo:1;
-+ unsigned multi_proc_int:1;
-+ unsigned reserved21:1;
-+ unsigned nonperio_tx_q_depth:2;
-+ unsigned host_perio_tx_q_depth:2;
-+ unsigned dev_token_q_depth:5;
-+ unsigned otg_enable_ic_usb:1;
-+ } b;
-+} hwcfg2_data_t;
-+
-+/**
-+ * This union represents the bit fields in the User HW Config3
-+ * Register. Read the register into the <i>d32</i> element then read
-+ * out the bits using the <i>b</i>it elements.
-+ */
-+typedef union hwcfg3_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /* GHWCFG3 */
-+ unsigned xfer_size_cntr_width:4;
-+ unsigned packet_size_cntr_width:3;
-+ unsigned otg_func:1;
-+ unsigned i2c:1;
-+ unsigned vendor_ctrl_if:1;
-+ unsigned optional_features:1;
-+ unsigned synch_reset_type:1;
-+ unsigned adp_supp:1;
-+ unsigned otg_enable_hsic:1;
-+ unsigned bc_support:1;
-+ unsigned otg_lpm_en:1;
-+ unsigned dfifo_depth:16;
-+ } b;
-+} hwcfg3_data_t;
-+
-+/**
-+ * This union represents the bit fields in the User HW Config4
-+ * Register. Read the register into the <i>d32</i> element then read
-+ * out the bits using the <i>b</i>it elements.
-+ */
-+typedef union hwcfg4_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned num_dev_perio_in_ep:4;
-+ unsigned power_optimiz:1;
-+ unsigned min_ahb_freq:1;
-+ unsigned hiber:1;
-+ unsigned xhiber:1;
-+ unsigned reserved:6;
-+ unsigned utmi_phy_data_width:2;
-+ unsigned num_dev_mode_ctrl_ep:4;
-+ unsigned iddig_filt_en:1;
-+ unsigned vbus_valid_filt_en:1;
-+ unsigned a_valid_filt_en:1;
-+ unsigned b_valid_filt_en:1;
-+ unsigned session_end_filt_en:1;
-+ unsigned ded_fifo_en:1;
-+ unsigned num_in_eps:4;
-+ unsigned desc_dma:1;
-+ unsigned desc_dma_dyn:1;
-+ } b;
-+} hwcfg4_data_t;
-+
-+/**
-+ * This union represents the bit fields of the Core LPM Configuration
-+ * Register (GLPMCFG). Set the bits using bit fields then write
-+ * the <i>d32</i> value to the register.
-+ */
-+typedef union glpmctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** LPM-Capable (LPMCap) (Device and Host)
-+ * The application uses this bit to control
-+ * the DWC_otg core LPM capabilities.
-+ */
-+ unsigned lpm_cap_en:1;
-+ /** LPM response programmed by application (AppL1Res) (Device)
-+ * Handshake response to LPM token pre-programmed
-+ * by device application software.
-+ */
-+ unsigned appl_resp:1;
-+ /** Host Initiated Resume Duration (HIRD) (Device and Host)
-+ * In Host mode this field indicates the value of HIRD
-+ * to be sent in an LPM transaction.
-+ * In Device mode this field is updated with the
-+ * Received LPM Token HIRD bmAttribute
-+ * when an ACK/NYET/STALL response is sent
-+ * to an LPM transaction.
-+ */
-+ unsigned hird:4;
-+ /** RemoteWakeEnable (bRemoteWake) (Device and Host)
-+ * In Host mode this bit indicates the value of remote
-+ * wake up to be sent in wIndex field of LPM transaction.
-+ * In Device mode this field is updated with the
-+ * Received LPM Token bRemoteWake bmAttribute
-+ * when an ACK/NYET/STALL response is sent
-+ * to an LPM transaction.
-+ */
-+ unsigned rem_wkup_en:1;
-+ /** Enable utmi_sleep_n (EnblSlpM) (Device and Host)
-+ * The application uses this bit to control
-+ * the utmi_sleep_n assertion to the PHY when in L1 state.
-+ */
-+ unsigned en_utmi_sleep:1;
-+ /** HIRD Threshold (HIRD_Thres) (Device and Host)
-+ */
-+ unsigned hird_thres:5;
-+ /** LPM Response (CoreL1Res) (Device and Host)
-+ * In Host mode this bit contains handsake response to
-+ * LPM transaction.
-+ * In Device mode the response of the core to
-+ * LPM transaction received is reflected in these two bits.
-+ - 0x0 : ERROR (No handshake response)
-+ - 0x1 : STALL
-+ - 0x2 : NYET
-+ - 0x3 : ACK
-+ */
-+ unsigned lpm_resp:2;
-+ /** Port Sleep Status (SlpSts) (Device and Host)
-+ * This bit is set as long as a Sleep condition
-+ * is present on the USB bus.
-+ */
-+ unsigned prt_sleep_sts:1;
-+ /** Sleep State Resume OK (L1ResumeOK) (Device and Host)
-+ * Indicates that the application or host
-+ * can start resume from Sleep state.
-+ */
-+ unsigned sleep_state_resumeok:1;
-+ /** LPM channel Index (LPM_Chnl_Indx) (Host)
-+ * The channel number on which the LPM transaction
-+ * has to be applied while sending
-+ * an LPM transaction to the local device.
-+ */
-+ unsigned lpm_chan_index:4;
-+ /** LPM Retry Count (LPM_Retry_Cnt) (Host)
-+ * Number host retries that would be performed
-+ * if the device response was not valid response.
-+ */
-+ unsigned retry_count:3;
-+ /** Send LPM Transaction (SndLPM) (Host)
-+ * When set by application software,
-+ * an LPM transaction containing two tokens
-+ * is sent.
-+ */
-+ unsigned send_lpm:1;
-+ /** LPM Retry status (LPM_RetryCnt_Sts) (Host)
-+ * Number of LPM Host Retries still remaining
-+ * to be transmitted for the current LPM sequence
-+ */
-+ unsigned retry_count_sts:3;
-+ unsigned reserved28_29:2;
-+ /** In host mode once this bit is set, the host
-+ * configures to drive the HSIC Idle state on the bus.
-+ * It then waits for the device to initiate the Connect sequence.
-+ * In device mode once this bit is set, the device waits for
-+ * the HSIC Idle line state on the bus. Upon receving the Idle
-+ * line state, it initiates the HSIC Connect sequence.
-+ */
-+ unsigned hsic_connect:1;
-+ /** This bit overrides and functionally inverts
-+ * the if_select_hsic input port signal.
-+ */
-+ unsigned inv_sel_hsic:1;
-+ } b;
-+} glpmcfg_data_t;
-+
-+/**
-+ * This union represents the bit fields of the Core ADP Timer, Control and
-+ * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write
-+ * the <i>d32</i> value to the register.
-+ */
-+typedef union adpctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Probe Discharge (PRB_DSCHG)
-+ * These bits set the times for TADP_DSCHG.
-+ * These bits are defined as follows:
-+ * 2'b00 - 4 msec
-+ * 2'b01 - 8 msec
-+ * 2'b10 - 16 msec
-+ * 2'b11 - 32 msec
-+ */
-+ unsigned prb_dschg:2;
-+ /** Probe Delta (PRB_DELTA)
-+ * These bits set the resolution for RTIM value.
-+ * The bits are defined in units of 32 kHz clock cycles as follows:
-+ * 2'b00 - 1 cycles
-+ * 2'b01 - 2 cycles
-+ * 2'b10 - 3 cycles
-+ * 2'b11 - 4 cycles
-+ * For example if this value is chosen to 2'b01, it means that RTIM
-+ * increments for every 3(three) 32Khz clock cycles.
-+ */
-+ unsigned prb_delta:2;
-+ /** Probe Period (PRB_PER)
-+ * These bits sets the TADP_PRD as shown in Figure 4 as follows:
-+ * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec)
-+ * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec)
-+ * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec)
-+ * 2'b11 - Reserved
-+ */
-+ unsigned prb_per:2;
-+ /** These bits capture the latest time it took for VBUS to ramp from
-+ * VADP_SINK to VADP_PRB.
-+ * 0x000 - 1 cycles
-+ * 0x001 - 2 cycles
-+ * 0x002 - 3 cycles
-+ * etc
-+ * 0x7FF - 2048 cycles
-+ * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec.
-+ */
-+ unsigned rtim:11;
-+ /** Enable Probe (EnaPrb)
-+ * When programmed to 1'b1, the core performs a probe operation.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned enaprb:1;
-+ /** Enable Sense (EnaSns)
-+ * When programmed to 1'b1, the core performs a Sense operation.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned enasns:1;
-+ /** ADP Reset (ADPRes)
-+ * When set, ADP controller is reset.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adpres:1;
-+ /** ADP Enable (ADPEn)
-+ * When set, the core performs either ADP probing or sensing
-+ * based on EnaPrb or EnaSns.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adpen:1;
-+ /** ADP Probe Interrupt (ADP_PRB_INT)
-+ * When this bit is set, it means that the VBUS
-+ * voltage is greater than VADP_PRB or VADP_PRB is reached.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adp_prb_int:1;
-+ /**
-+ * ADP Sense Interrupt (ADP_SNS_INT)
-+ * When this bit is set, it means that the VBUS voltage is greater than
-+ * VADP_SNS value or VADP_SNS is reached.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adp_sns_int:1;
-+ /** ADP Tomeout Interrupt (ADP_TMOUT_INT)
-+ * This bit is relevant only for an ADP probe.
-+ * When this bit is set, it means that the ramp time has
-+ * completed ie ADPCTL.RTIM has reached its terminal value
-+ * of 0x7FF. This is a debug feature that allows software
-+ * to read the ramp time after each cycle.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adp_tmout_int:1;
-+ /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK)
-+ * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adp_prb_int_msk:1;
-+ /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK)
-+ * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adp_sns_int_msk:1;
-+ /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK)
-+ * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT.
-+ * This bit is valid only if OTG_Ver = 1'b1.
-+ */
-+ unsigned adp_tmout_int_msk:1;
-+ /** Access Request
-+ * 2'b00 - Read/Write Valid (updated by the core)
-+ * 2'b01 - Read
-+ * 2'b00 - Write
-+ * 2'b00 - Reserved
-+ */
-+ unsigned ar:2;
-+ /** Reserved */
-+ unsigned reserved29_31:3;
-+ } b;
-+} adpctl_data_t;
-+
-+////////////////////////////////////////////
-+// Device Registers
-+/**
-+ * Device Global Registers. <i>Offsets 800h-BFFh</i>
-+ *
-+ * The following structures define the size and relative field offsets
-+ * for the Device Mode Registers.
-+ *
-+ * <i>These registers are visible only in Device mode and must not be
-+ * accessed in Host mode, as the results are unknown.</i>
-+ */
-+typedef struct dwc_otg_dev_global_regs {
-+ /** Device Configuration Register. <i>Offset 800h</i> */
-+ volatile uint32_t dcfg;
-+ /** Device Control Register. <i>Offset: 804h</i> */
-+ volatile uint32_t dctl;
-+ /** Device Status Register (Read Only). <i>Offset: 808h</i> */
-+ volatile uint32_t dsts;
-+ /** Reserved. <i>Offset: 80Ch</i> */
-+ uint32_t unused;
-+ /** Device IN Endpoint Common Interrupt Mask
-+ * Register. <i>Offset: 810h</i> */
-+ volatile uint32_t diepmsk;
-+ /** Device OUT Endpoint Common Interrupt Mask
-+ * Register. <i>Offset: 814h</i> */
-+ volatile uint32_t doepmsk;
-+ /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
-+ volatile uint32_t daint;
-+ /** Device All Endpoints Interrupt Mask Register. <i>Offset:
-+ * 81Ch</i> */
-+ volatile uint32_t daintmsk;
-+ /** Device IN Token Queue Read Register-1 (Read Only).
-+ * <i>Offset: 820h</i> */
-+ volatile uint32_t dtknqr1;
-+ /** Device IN Token Queue Read Register-2 (Read Only).
-+ * <i>Offset: 824h</i> */
-+ volatile uint32_t dtknqr2;
-+ /** Device VBUS discharge Register. <i>Offset: 828h</i> */
-+ volatile uint32_t dvbusdis;
-+ /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
-+ volatile uint32_t dvbuspulse;
-+ /** Device IN Token Queue Read Register-3 (Read Only). /
-+ * Device Thresholding control register (Read/Write)
-+ * <i>Offset: 830h</i> */
-+ volatile uint32_t dtknqr3_dthrctl;
-+ /** Device IN Token Queue Read Register-4 (Read Only). /
-+ * Device IN EPs empty Inr. Mask Register (Read/Write)
-+ * <i>Offset: 834h</i> */
-+ volatile uint32_t dtknqr4_fifoemptymsk;
-+ /** Device Each Endpoint Interrupt Register (Read Only). /
-+ * <i>Offset: 838h</i> */
-+ volatile uint32_t deachint;
-+ /** Device Each Endpoint Interrupt mask Register (Read/Write). /
-+ * <i>Offset: 83Ch</i> */
-+ volatile uint32_t deachintmsk;
-+ /** Device Each In Endpoint Interrupt mask Register (Read/Write). /
-+ * <i>Offset: 840h</i> */
-+ volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
-+ /** Device Each Out Endpoint Interrupt mask Register (Read/Write). /
-+ * <i>Offset: 880h</i> */
-+ volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
-+} dwc_otg_device_global_regs_t;
-+
-+/**
-+ * This union represents the bit fields in the Device Configuration
-+ * Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements. Write the
-+ * <i>d32</i> member to the dcfg register.
-+ */
-+typedef union dcfg_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Device Speed */
-+ unsigned devspd:2;
-+ /** Non Zero Length Status OUT Handshake */
-+ unsigned nzstsouthshk:1;
-+#define DWC_DCFG_SEND_STALL 1
-+
-+ unsigned ena32khzs:1;
-+ /** Device Addresses */
-+ unsigned devaddr:7;
-+ /** Periodic Frame Interval */
-+ unsigned perfrint:2;
-+#define DWC_DCFG_FRAME_INTERVAL_80 0
-+#define DWC_DCFG_FRAME_INTERVAL_85 1
-+#define DWC_DCFG_FRAME_INTERVAL_90 2
-+#define DWC_DCFG_FRAME_INTERVAL_95 3
-+
-+ /** Enable Device OUT NAK for bulk in DDMA mode */
-+ unsigned endevoutnak:1;
-+
-+ unsigned reserved14_17:4;
-+ /** In Endpoint Mis-match count */
-+ unsigned epmscnt:5;
-+ /** Enable Descriptor DMA in Device mode */
-+ unsigned descdma:1;
-+ unsigned perschintvl:2;
-+ unsigned resvalid:6;
-+ } b;
-+} dcfg_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device Control
-+ * Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union dctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Remote Wakeup */
-+ unsigned rmtwkupsig:1;
-+ /** Soft Disconnect */
-+ unsigned sftdiscon:1;
-+ /** Global Non-Periodic IN NAK Status */
-+ unsigned gnpinnaksts:1;
-+ /** Global OUT NAK Status */
-+ unsigned goutnaksts:1;
-+ /** Test Control */
-+ unsigned tstctl:3;
-+ /** Set Global Non-Periodic IN NAK */
-+ unsigned sgnpinnak:1;
-+ /** Clear Global Non-Periodic IN NAK */
-+ unsigned cgnpinnak:1;
-+ /** Set Global OUT NAK */
-+ unsigned sgoutnak:1;
-+ /** Clear Global OUT NAK */
-+ unsigned cgoutnak:1;
-+ /** Power-On Programming Done */
-+ unsigned pwronprgdone:1;
-+ /** Reserved */
-+ unsigned reserved:1;
-+ /** Global Multi Count */
-+ unsigned gmc:2;
-+ /** Ignore Frame Number for ISOC EPs */
-+ unsigned ifrmnum:1;
-+ /** NAK on Babble */
-+ unsigned nakonbble:1;
-+ /** Enable Continue on BNA */
-+ unsigned encontonbna:1;
-+
-+ unsigned reserved18_31:14;
-+ } b;
-+} dctl_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device Status
-+ * Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union dsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Suspend Status */
-+ unsigned suspsts:1;
-+ /** Enumerated Speed */
-+ unsigned enumspd:2;
-+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
-+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
-+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
-+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
-+ /** Erratic Error */
-+ unsigned errticerr:1;
-+ unsigned reserved4_7:4;
-+ /** Frame or Microframe Number of the received SOF */
-+ unsigned soffn:14;
-+ unsigned reserved22_31:10;
-+ } b;
-+} dsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device IN EP Interrupt
-+ * Register and the Device IN EP Common Mask Register.
-+ *
-+ * - Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union diepint_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Transfer complete mask */
-+ unsigned xfercompl:1;
-+ /** Endpoint disable mask */
-+ unsigned epdisabled:1;
-+ /** AHB Error mask */
-+ unsigned ahberr:1;
-+ /** TimeOUT Handshake mask (non-ISOC EPs) */
-+ unsigned timeout:1;
-+ /** IN Token received with TxF Empty mask */
-+ unsigned intktxfemp:1;
-+ /** IN Token Received with EP mismatch mask */
-+ unsigned intknepmis:1;
-+ /** IN Endpoint NAK Effective mask */
-+ unsigned inepnakeff:1;
-+ /** Reserved */
-+ unsigned emptyintr:1;
-+
-+ unsigned txfifoundrn:1;
-+
-+ /** BNA Interrupt mask */
-+ unsigned bna:1;
-+
-+ unsigned reserved10_12:3;
-+ /** BNA Interrupt mask */
-+ unsigned nak:1;
-+
-+ unsigned reserved14_31:18;
-+ } b;
-+} diepint_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device IN EP
-+ * Common/Dedicated Interrupt Mask Register.
-+ */
-+typedef union diepint_data diepmsk_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device OUT EP Interrupt
-+ * Registerand Device OUT EP Common Interrupt Mask Register.
-+ *
-+ * - Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union doepint_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Transfer complete */
-+ unsigned xfercompl:1;
-+ /** Endpoint disable */
-+ unsigned epdisabled:1;
-+ /** AHB Error */
-+ unsigned ahberr:1;
-+ /** Setup Phase Done (contorl EPs) */
-+ unsigned setup:1;
-+ /** OUT Token Received when Endpoint Disabled */
-+ unsigned outtknepdis:1;
-+
-+ unsigned stsphsercvd:1;
-+ /** Back-to-Back SETUP Packets Received */
-+ unsigned back2backsetup:1;
-+
-+ unsigned reserved7:1;
-+ /** OUT packet Error */
-+ unsigned outpkterr:1;
-+ /** BNA Interrupt */
-+ unsigned bna:1;
-+
-+ unsigned reserved10:1;
-+ /** Packet Drop Status */
-+ unsigned pktdrpsts:1;
-+ /** Babble Interrupt */
-+ unsigned babble:1;
-+ /** NAK Interrupt */
-+ unsigned nak:1;
-+ /** NYET Interrupt */
-+ unsigned nyet:1;
-+ /** Bit indicating setup packet received */
-+ unsigned sr:1;
-+
-+ unsigned reserved16_31:16;
-+ } b;
-+} doepint_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device OUT EP
-+ * Common/Dedicated Interrupt Mask Register.
-+ */
-+typedef union doepint_data doepmsk_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device All EP Interrupt
-+ * and Mask Registers.
-+ * - Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union daint_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** IN Endpoint bits */
-+ unsigned in:16;
-+ /** OUT Endpoint bits */
-+ unsigned out:16;
-+ } ep;
-+ struct {
-+ /** IN Endpoint bits */
-+ unsigned inep0:1;
-+ unsigned inep1:1;
-+ unsigned inep2:1;
-+ unsigned inep3:1;
-+ unsigned inep4:1;
-+ unsigned inep5:1;
-+ unsigned inep6:1;
-+ unsigned inep7:1;
-+ unsigned inep8:1;
-+ unsigned inep9:1;
-+ unsigned inep10:1;
-+ unsigned inep11:1;
-+ unsigned inep12:1;
-+ unsigned inep13:1;
-+ unsigned inep14:1;
-+ unsigned inep15:1;
-+ /** OUT Endpoint bits */
-+ unsigned outep0:1;
-+ unsigned outep1:1;
-+ unsigned outep2:1;
-+ unsigned outep3:1;
-+ unsigned outep4:1;
-+ unsigned outep5:1;
-+ unsigned outep6:1;
-+ unsigned outep7:1;
-+ unsigned outep8:1;
-+ unsigned outep9:1;
-+ unsigned outep10:1;
-+ unsigned outep11:1;
-+ unsigned outep12:1;
-+ unsigned outep13:1;
-+ unsigned outep14:1;
-+ unsigned outep15:1;
-+ } b;
-+} daint_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device IN Token Queue
-+ * Read Registers.
-+ * - Read the register into the <i>d32</i> member.
-+ * - READ-ONLY Register
-+ */
-+typedef union dtknq1_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** In Token Queue Write Pointer */
-+ unsigned intknwptr:5;
-+ /** Reserved */
-+ unsigned reserved05_06:2;
-+ /** write pointer has wrapped. */
-+ unsigned wrap_bit:1;
-+ /** EP Numbers of IN Tokens 0 ... 4 */
-+ unsigned epnums0_5:24;
-+ } b;
-+} dtknq1_data_t;
-+
-+/**
-+ * This union represents Threshold control Register
-+ * - Read and write the register into the <i>d32</i> member.
-+ * - READ-WRITABLE Register
-+ */
-+typedef union dthrctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** non ISO Tx Thr. Enable */
-+ unsigned non_iso_thr_en:1;
-+ /** ISO Tx Thr. Enable */
-+ unsigned iso_thr_en:1;
-+ /** Tx Thr. Length */
-+ unsigned tx_thr_len:9;
-+ /** AHB Threshold ratio */
-+ unsigned ahb_thr_ratio:2;
-+ /** Reserved */
-+ unsigned reserved13_15:3;
-+ /** Rx Thr. Enable */
-+ unsigned rx_thr_en:1;
-+ /** Rx Thr. Length */
-+ unsigned rx_thr_len:9;
-+ unsigned reserved26:1;
-+ /** Arbiter Parking Enable*/
-+ unsigned arbprken:1;
-+ /** Reserved */
-+ unsigned reserved28_31:4;
-+ } b;
-+} dthrctl_data_t;
-+
-+/**
-+ * Device Logical IN Endpoint-Specific Registers. <i>Offsets
-+ * 900h-AFCh</i>
-+ *
-+ * There will be one set of endpoint registers per logical endpoint
-+ * implemented.
-+ *
-+ * <i>These registers are visible only in Device mode and must not be
-+ * accessed in Host mode, as the results are unknown.</i>
-+ */
-+typedef struct dwc_otg_dev_in_ep_regs {
-+ /** Device IN Endpoint Control Register. <i>Offset:900h +
-+ * (ep_num * 20h) + 00h</i> */
-+ volatile uint32_t diepctl;
-+ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
-+ uint32_t reserved04;
-+ /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
-+ * (ep_num * 20h) + 08h</i> */
-+ volatile uint32_t diepint;
-+ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
-+ uint32_t reserved0C;
-+ /** Device IN Endpoint Transfer Size
-+ * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
-+ volatile uint32_t dieptsiz;
-+ /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
-+ * (ep_num * 20h) + 14h</i> */
-+ volatile uint32_t diepdma;
-+ /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
-+ * (ep_num * 20h) + 18h</i> */
-+ volatile uint32_t dtxfsts;
-+ /** Device IN Endpoint DMA Buffer Register. <i>Offset:900h +
-+ * (ep_num * 20h) + 1Ch</i> */
-+ volatile uint32_t diepdmab;
-+} dwc_otg_dev_in_ep_regs_t;
-+
-+/**
-+ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
-+ * B00h-CFCh</i>
-+ *
-+ * There will be one set of endpoint registers per logical endpoint
-+ * implemented.
-+ *
-+ * <i>These registers are visible only in Device mode and must not be
-+ * accessed in Host mode, as the results are unknown.</i>
-+ */
-+typedef struct dwc_otg_dev_out_ep_regs {
-+ /** Device OUT Endpoint Control Register. <i>Offset:B00h +
-+ * (ep_num * 20h) + 00h</i> */
-+ volatile uint32_t doepctl;
-+ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 04h</i> */
-+ uint32_t reserved04;
-+ /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
-+ * (ep_num * 20h) + 08h</i> */
-+ volatile uint32_t doepint;
-+ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
-+ uint32_t reserved0C;
-+ /** Device OUT Endpoint Transfer Size Register. <i>Offset:
-+ * B00h + (ep_num * 20h) + 10h</i> */
-+ volatile uint32_t doeptsiz;
-+ /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
-+ * + (ep_num * 20h) + 14h</i> */
-+ volatile uint32_t doepdma;
-+ /** Reserved. <i>Offset:B00h + * (ep_num * 20h) + 18h</i> */
-+ uint32_t unused;
-+ /** Device OUT Endpoint DMA Buffer Register. <i>Offset:B00h
-+ * + (ep_num * 20h) + 1Ch</i> */
-+ uint32_t doepdmab;
-+} dwc_otg_dev_out_ep_regs_t;
-+
-+/**
-+ * This union represents the bit fields in the Device EP Control
-+ * Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union depctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Maximum Packet Size
-+ * IN/OUT EPn
-+ * IN/OUT EP0 - 2 bits
-+ * 2'b00: 64 Bytes
-+ * 2'b01: 32
-+ * 2'b10: 16
-+ * 2'b11: 8 */
-+ unsigned mps:11;
-+#define DWC_DEP0CTL_MPS_64 0
-+#define DWC_DEP0CTL_MPS_32 1
-+#define DWC_DEP0CTL_MPS_16 2
-+#define DWC_DEP0CTL_MPS_8 3
-+
-+ /** Next Endpoint
-+ * IN EPn/IN EP0
-+ * OUT EPn/OUT EP0 - reserved */
-+ unsigned nextep:4;
-+
-+ /** USB Active Endpoint */
-+ unsigned usbactep:1;
-+
-+ /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
-+ * This field contains the PID of the packet going to
-+ * be received or transmitted on this endpoint. The
-+ * application should program the PID of the first
-+ * packet going to be received or transmitted on this
-+ * endpoint , after the endpoint is
-+ * activated. Application use the SetD1PID and
-+ * SetD0PID fields of this register to program either
-+ * D0 or D1 PID.
-+ *
-+ * The encoding for this field is
-+ * - 0: D0
-+ * - 1: D1
-+ */
-+ unsigned dpid:1;
-+
-+ /** NAK Status */
-+ unsigned naksts:1;
-+
-+ /** Endpoint Type
-+ * 2'b00: Control
-+ * 2'b01: Isochronous
-+ * 2'b10: Bulk
-+ * 2'b11: Interrupt */
-+ unsigned eptype:2;
-+
-+ /** Snoop Mode
-+ * OUT EPn/OUT EP0
-+ * IN EPn/IN EP0 - reserved */
-+ unsigned snp:1;
-+
-+ /** Stall Handshake */
-+ unsigned stall:1;
-+
-+ /** Tx Fifo Number
-+ * IN EPn/IN EP0
-+ * OUT EPn/OUT EP0 - reserved */
-+ unsigned txfnum:4;
-+
-+ /** Clear NAK */
-+ unsigned cnak:1;
-+ /** Set NAK */
-+ unsigned snak:1;
-+ /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
-+ * Writing to this field sets the Endpoint DPID (DPID)
-+ * field in this register to DATA0. Set Even
-+ * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
-+ * Writing to this field sets the Even/Odd
-+ * (micro)frame (EO_FrNum) field to even (micro)
-+ * frame.
-+ */
-+ unsigned setd0pid:1;
-+ /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
-+ * Writing to this field sets the Endpoint DPID (DPID)
-+ * field in this register to DATA1 Set Odd
-+ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
-+ * Writing to this field sets the Even/Odd
-+ * (micro)frame (EO_FrNum) field to odd (micro) frame.
-+ */
-+ unsigned setd1pid:1;
-+
-+ /** Endpoint Disable */
-+ unsigned epdis:1;
-+ /** Endpoint Enable */
-+ unsigned epena:1;
-+ } b;
-+} depctl_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device EP Transfer
-+ * Size Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union deptsiz_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Transfer size */
-+ unsigned xfersize:19;
-+/** Max packet count for EP (pow(2,10)-1) */
-+#define MAX_PKT_CNT 1023
-+ /** Packet Count */
-+ unsigned pktcnt:10;
-+ /** Multi Count - Periodic IN endpoints */
-+ unsigned mc:2;
-+ unsigned reserved:1;
-+ } b;
-+} deptsiz_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Device EP 0 Transfer
-+ * Size Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union deptsiz0_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Transfer size */
-+ unsigned xfersize:7;
-+ /** Reserved */
-+ unsigned reserved7_18:12;
-+ /** Packet Count */
-+ unsigned pktcnt:2;
-+ /** Reserved */
-+ unsigned reserved21_28:8;
-+ /**Setup Packet Count (DOEPTSIZ0 Only) */
-+ unsigned supcnt:2;
-+ unsigned reserved31;
-+ } b;
-+} deptsiz0_data_t;
-+
-+/////////////////////////////////////////////////
-+// DMA Descriptor Specific Structures
-+//
-+
-+/** Buffer status definitions */
-+
-+#define BS_HOST_READY 0x0
-+#define BS_DMA_BUSY 0x1
-+#define BS_DMA_DONE 0x2
-+#define BS_HOST_BUSY 0x3
-+
-+/** Receive/Transmit status definitions */
-+
-+#define RTS_SUCCESS 0x0
-+#define RTS_BUFFLUSH 0x1
-+#define RTS_RESERVED 0x2
-+#define RTS_BUFERR 0x3
-+
-+/**
-+ * This union represents the bit fields in the DMA Descriptor
-+ * status quadlet. Read the quadlet into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it, <i>b_iso_out</i> and
-+ * <i>b_iso_in</i> elements.
-+ */
-+typedef union dev_dma_desc_sts {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** quadlet bits */
-+ struct {
-+ /** Received number of bytes */
-+ unsigned bytes:16;
-+ /** NAK bit - only for OUT EPs */
-+ unsigned nak:1;
-+ unsigned reserved17_22:6;
-+ /** Multiple Transfer - only for OUT EPs */
-+ unsigned mtrf:1;
-+ /** Setup Packet received - only for OUT EPs */
-+ unsigned sr:1;
-+ /** Interrupt On Complete */
-+ unsigned ioc:1;
-+ /** Short Packet */
-+ unsigned sp:1;
-+ /** Last */
-+ unsigned l:1;
-+ /** Receive Status */
-+ unsigned sts:2;
-+ /** Buffer Status */
-+ unsigned bs:2;
-+ } b;
-+
-+//#ifdef DWC_EN_ISOC
-+ /** iso out quadlet bits */
-+ struct {
-+ /** Received number of bytes */
-+ unsigned rxbytes:11;
-+
-+ unsigned reserved11:1;
-+ /** Frame Number */
-+ unsigned framenum:11;
-+ /** Received ISO Data PID */
-+ unsigned pid:2;
-+ /** Interrupt On Complete */
-+ unsigned ioc:1;
-+ /** Short Packet */
-+ unsigned sp:1;
-+ /** Last */
-+ unsigned l:1;
-+ /** Receive Status */
-+ unsigned rxsts:2;
-+ /** Buffer Status */
-+ unsigned bs:2;
-+ } b_iso_out;
-+
-+ /** iso in quadlet bits */
-+ struct {
-+ /** Transmited number of bytes */
-+ unsigned txbytes:12;
-+ /** Frame Number */
-+ unsigned framenum:11;
-+ /** Transmited ISO Data PID */
-+ unsigned pid:2;
-+ /** Interrupt On Complete */
-+ unsigned ioc:1;
-+ /** Short Packet */
-+ unsigned sp:1;
-+ /** Last */
-+ unsigned l:1;
-+ /** Transmit Status */
-+ unsigned txsts:2;
-+ /** Buffer Status */
-+ unsigned bs:2;
-+ } b_iso_in;
-+//#endif /* DWC_EN_ISOC */
-+} dev_dma_desc_sts_t;
-+
-+/**
-+ * DMA Descriptor structure
-+ *
-+ * DMA Descriptor structure contains two quadlets:
-+ * Status quadlet and Data buffer pointer.
-+ */
-+typedef struct dwc_otg_dev_dma_desc {
-+ /** DMA Descriptor status quadlet */
-+ dev_dma_desc_sts_t status;
-+ /** DMA Descriptor data buffer pointer */
-+ uint32_t buf;
-+} dwc_otg_dev_dma_desc_t;
-+
-+/**
-+ * The dwc_otg_dev_if structure contains information needed to manage
-+ * the DWC_otg controller acting in device mode. It represents the
-+ * programming view of the device-specific aspects of the controller.
-+ */
-+typedef struct dwc_otg_dev_if {
-+ /** Pointer to device Global registers.
-+ * Device Global Registers starting at offset 800h
-+ */
-+ dwc_otg_device_global_regs_t *dev_global_regs;
-+#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
-+
-+ /**
-+ * Device Logical IN Endpoint-Specific Registers 900h-AFCh
-+ */
-+ dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
-+#define DWC_DEV_IN_EP_REG_OFFSET 0x900
-+#define DWC_EP_REG_OFFSET 0x20
-+
-+ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
-+ dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
-+#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
-+
-+ /* Device configuration information */
-+ uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
-+ uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
-+ uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
-+
-+ /** Size of periodic FIFOs (Bytes) */
-+ uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
-+
-+ /** Size of Tx FIFOs (Bytes) */
-+ uint16_t tx_fifo_size[MAX_TX_FIFOS];
-+
-+ /** Thresholding enable flags and length varaiables **/
-+ uint16_t rx_thr_en;
-+ uint16_t iso_tx_thr_en;
-+ uint16_t non_iso_tx_thr_en;
-+
-+ uint16_t rx_thr_length;
-+ uint16_t tx_thr_length;
-+
-+ /**
-+ * Pointers to the DMA Descriptors for EP0 Control
-+ * transfers (virtual and physical)
-+ */
-+
-+ /** 2 descriptors for SETUP packets */
-+ dwc_dma_t dma_setup_desc_addr[2];
-+ dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
-+
-+ /** Pointer to Descriptor with latest SETUP packet */
-+ dwc_otg_dev_dma_desc_t *psetup;
-+
-+ /** Index of current SETUP handler descriptor */
-+ uint32_t setup_desc_index;
-+
-+ /** Descriptor for Data In or Status In phases */
-+ dwc_dma_t dma_in_desc_addr;
-+ dwc_otg_dev_dma_desc_t *in_desc_addr;
-+
-+ /** Descriptor for Data Out or Status Out phases */
-+ dwc_dma_t dma_out_desc_addr;
-+ dwc_otg_dev_dma_desc_t *out_desc_addr;
-+
-+ /** Setup Packet Detected - if set clear NAK when queueing */
-+ uint32_t spd;
-+ /** Isoc ep pointer on which incomplete happens */
-+ void *isoc_ep;
-+
-+} dwc_otg_dev_if_t;
-+
-+/////////////////////////////////////////////////
-+// Host Mode Register Structures
-+//
-+/**
-+ * The Host Global Registers structure defines the size and relative
-+ * field offsets for the Host Mode Global Registers. Host Global
-+ * Registers offsets 400h-7FFh.
-+*/
-+typedef struct dwc_otg_host_global_regs {
-+ /** Host Configuration Register. <i>Offset: 400h</i> */
-+ volatile uint32_t hcfg;
-+ /** Host Frame Interval Register. <i>Offset: 404h</i> */
-+ volatile uint32_t hfir;
-+ /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
-+ volatile uint32_t hfnum;
-+ /** Reserved. <i>Offset: 40Ch</i> */
-+ uint32_t reserved40C;
-+ /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
-+ volatile uint32_t hptxsts;
-+ /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
-+ volatile uint32_t haint;
-+ /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
-+ volatile uint32_t haintmsk;
-+ /** Host Frame List Base Address Register . <i>Offset: 41Ch</i> */
-+ volatile uint32_t hflbaddr;
-+} dwc_otg_host_global_regs_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Configuration Register.
-+ * Read the register into the <i>d32</i> member then set/clear the bits using
-+ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
-+ */
-+typedef union hcfg_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ /** FS/LS Phy Clock Select */
-+ unsigned fslspclksel:2;
-+#define DWC_HCFG_30_60_MHZ 0
-+#define DWC_HCFG_48_MHZ 1
-+#define DWC_HCFG_6_MHZ 2
-+
-+ /** FS/LS Only Support */
-+ unsigned fslssupp:1;
-+ unsigned reserved3_6:4;
-+ /** Enable 32-KHz Suspend Mode */
-+ unsigned ena32khzs:1;
-+ /** Resume Validation Periiod */
-+ unsigned resvalid:8;
-+ unsigned reserved16_22:7;
-+ /** Enable Scatter/gather DMA in Host mode */
-+ unsigned descdma:1;
-+ /** Frame List Entries */
-+ unsigned frlisten:2;
-+ /** Enable Periodic Scheduling */
-+ unsigned perschedena:1;
-+ unsigned reserved27_30:4;
-+ unsigned modechtimen:1;
-+ } b;
-+} hcfg_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Frame Remaing/Number
-+ * Register.
-+ */
-+typedef union hfir_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ unsigned frint:16;
-+ unsigned hfirrldctrl:1;
-+ unsigned reserved:15;
-+ } b;
-+} hfir_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Frame Remaing/Number
-+ * Register.
-+ */
-+typedef union hfnum_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ unsigned frnum:16;
-+#define DWC_HFNUM_MAX_FRNUM 0x3FFF
-+ unsigned frrem:16;
-+ } b;
-+} hfnum_data_t;
-+
-+typedef union hptxsts_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ unsigned ptxfspcavail:16;
-+ unsigned ptxqspcavail:8;
-+ /** Top of the Periodic Transmit Request Queue
-+ * - bit 24 - Terminate (last entry for the selected channel)
-+ * - bits 26:25 - Token Type
-+ * - 2'b00 - Zero length
-+ * - 2'b01 - Ping
-+ * - 2'b10 - Disable
-+ * - bits 30:27 - Channel Number
-+ * - bit 31 - Odd/even microframe
-+ */
-+ unsigned ptxqtop_terminate:1;
-+ unsigned ptxqtop_token:2;
-+ unsigned ptxqtop_chnum:4;
-+ unsigned ptxqtop_odd:1;
-+ } b;
-+} hptxsts_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Port Control and Status
-+ * Register. Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
-+ * hprt0 register.
-+ */
-+typedef union hprt0_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned prtconnsts:1;
-+ unsigned prtconndet:1;
-+ unsigned prtena:1;
-+ unsigned prtenchng:1;
-+ unsigned prtovrcurract:1;
-+ unsigned prtovrcurrchng:1;
-+ unsigned prtres:1;
-+ unsigned prtsusp:1;
-+ unsigned prtrst:1;
-+ unsigned reserved9:1;
-+ unsigned prtlnsts:2;
-+ unsigned prtpwr:1;
-+ unsigned prttstctl:4;
-+ unsigned prtspd:2;
-+#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
-+#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
-+#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
-+ unsigned reserved19_31:13;
-+ } b;
-+} hprt0_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host All Interrupt
-+ * Register.
-+ */
-+typedef union haint_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned ch0:1;
-+ unsigned ch1:1;
-+ unsigned ch2:1;
-+ unsigned ch3:1;
-+ unsigned ch4:1;
-+ unsigned ch5:1;
-+ unsigned ch6:1;
-+ unsigned ch7:1;
-+ unsigned ch8:1;
-+ unsigned ch9:1;
-+ unsigned ch10:1;
-+ unsigned ch11:1;
-+ unsigned ch12:1;
-+ unsigned ch13:1;
-+ unsigned ch14:1;
-+ unsigned ch15:1;
-+ unsigned reserved:16;
-+ } b;
-+
-+ struct {
-+ unsigned chint:16;
-+ unsigned reserved:16;
-+ } b2;
-+} haint_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host All Interrupt
-+ * Register.
-+ */
-+typedef union haintmsk_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned ch0:1;
-+ unsigned ch1:1;
-+ unsigned ch2:1;
-+ unsigned ch3:1;
-+ unsigned ch4:1;
-+ unsigned ch5:1;
-+ unsigned ch6:1;
-+ unsigned ch7:1;
-+ unsigned ch8:1;
-+ unsigned ch9:1;
-+ unsigned ch10:1;
-+ unsigned ch11:1;
-+ unsigned ch12:1;
-+ unsigned ch13:1;
-+ unsigned ch14:1;
-+ unsigned ch15:1;
-+ unsigned reserved:16;
-+ } b;
-+
-+ struct {
-+ unsigned chint:16;
-+ unsigned reserved:16;
-+ } b2;
-+} haintmsk_data_t;
-+
-+/**
-+ * Host Channel Specific Registers. <i>500h-5FCh</i>
-+ */
-+typedef struct dwc_otg_hc_regs {
-+ /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
-+ volatile uint32_t hcchar;
-+ /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
-+ volatile uint32_t hcsplt;
-+ /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
-+ volatile uint32_t hcint;
-+ /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
-+ volatile uint32_t hcintmsk;
-+ /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
-+ volatile uint32_t hctsiz;
-+ /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
-+ volatile uint32_t hcdma;
-+ volatile uint32_t reserved;
-+ /** Host Channel 0 DMA Buffer Address Register. <i>Offset: 500h + (chan_num * 20h) + 1Ch</i> */
-+ volatile uint32_t hcdmab;
-+} dwc_otg_hc_regs_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Channel Characteristics
-+ * Register. Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
-+ * hcchar register.
-+ */
-+typedef union hcchar_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ /** Maximum packet size in bytes */
-+ unsigned mps:11;
-+
-+ /** Endpoint number */
-+ unsigned epnum:4;
-+
-+ /** 0: OUT, 1: IN */
-+ unsigned epdir:1;
-+
-+ unsigned reserved:1;
-+
-+ /** 0: Full/high speed device, 1: Low speed device */
-+ unsigned lspddev:1;
-+
-+ /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
-+ unsigned eptype:2;
-+
-+ /** Packets per frame for periodic transfers. 0 is reserved. */
-+ unsigned multicnt:2;
-+
-+ /** Device address */
-+ unsigned devaddr:7;
-+
-+ /**
-+ * Frame to transmit periodic transaction.
-+ * 0: even, 1: odd
-+ */
-+ unsigned oddfrm:1;
-+
-+ /** Channel disable */
-+ unsigned chdis:1;
-+
-+ /** Channel enable */
-+ unsigned chen:1;
-+ } b;
-+} hcchar_data_t;
-+
-+typedef union hcsplt_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ /** Port Address */
-+ unsigned prtaddr:7;
-+
-+ /** Hub Address */
-+ unsigned hubaddr:7;
-+
-+ /** Transaction Position */
-+ unsigned xactpos:2;
-+#define DWC_HCSPLIT_XACTPOS_MID 0
-+#define DWC_HCSPLIT_XACTPOS_END 1
-+#define DWC_HCSPLIT_XACTPOS_BEGIN 2
-+#define DWC_HCSPLIT_XACTPOS_ALL 3
-+
-+ /** Do Complete Split */
-+ unsigned compsplt:1;
-+
-+ /** Reserved */
-+ unsigned reserved:14;
-+
-+ /** Split Enble */
-+ unsigned spltena:1;
-+ } b;
-+} hcsplt_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host All Interrupt
-+ * Register.
-+ */
-+typedef union hcint_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** Transfer Complete */
-+ unsigned xfercomp:1;
-+ /** Channel Halted */
-+ unsigned chhltd:1;
-+ /** AHB Error */
-+ unsigned ahberr:1;
-+ /** STALL Response Received */
-+ unsigned stall:1;
-+ /** NAK Response Received */
-+ unsigned nak:1;
-+ /** ACK Response Received */
-+ unsigned ack:1;
-+ /** NYET Response Received */
-+ unsigned nyet:1;
-+ /** Transaction Err */
-+ unsigned xacterr:1;
-+ /** Babble Error */
-+ unsigned bblerr:1;
-+ /** Frame Overrun */
-+ unsigned frmovrun:1;
-+ /** Data Toggle Error */
-+ unsigned datatglerr:1;
-+ /** Buffer Not Available (only for DDMA mode) */
-+ unsigned bna:1;
-+ /** Exessive transaction error (only for DDMA mode) */
-+ unsigned xcs_xact:1;
-+ /** Frame List Rollover interrupt */
-+ unsigned frm_list_roll:1;
-+ /** Reserved */
-+ unsigned reserved14_31:18;
-+ } b;
-+} hcint_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Channel Interrupt Mask
-+ * Register. Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
-+ * hcintmsk register.
-+ */
-+typedef union hcintmsk_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ unsigned xfercompl:1;
-+ unsigned chhltd:1;
-+ unsigned ahberr:1;
-+ unsigned stall:1;
-+ unsigned nak:1;
-+ unsigned ack:1;
-+ unsigned nyet:1;
-+ unsigned xacterr:1;
-+ unsigned bblerr:1;
-+ unsigned frmovrun:1;
-+ unsigned datatglerr:1;
-+ unsigned bna:1;
-+ unsigned xcs_xact:1;
-+ unsigned frm_list_roll:1;
-+ unsigned reserved14_31:18;
-+ } b;
-+} hcintmsk_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host Channel Transfer Size
-+ * Register. Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
-+ * hcchar register.
-+ */
-+
-+typedef union hctsiz_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ /** Total transfer size in bytes */
-+ unsigned xfersize:19;
-+
-+ /** Data packets to transfer */
-+ unsigned pktcnt:10;
-+
-+ /**
-+ * Packet ID for next data packet
-+ * 0: DATA0
-+ * 1: DATA2
-+ * 2: DATA1
-+ * 3: MDATA (non-Control), SETUP (Control)
-+ */
-+ unsigned pid:2;
-+#define DWC_HCTSIZ_DATA0 0
-+#define DWC_HCTSIZ_DATA1 2
-+#define DWC_HCTSIZ_DATA2 1
-+#define DWC_HCTSIZ_MDATA 3
-+#define DWC_HCTSIZ_SETUP 3
-+
-+ /** Do PING protocol when 1 */
-+ unsigned dopng:1;
-+ } b;
-+
-+ /** register bits */
-+ struct {
-+ /** Scheduling information */
-+ unsigned schinfo:8;
-+
-+ /** Number of transfer descriptors.
-+ * Max value:
-+ * 64 in general,
-+ * 256 only for HS isochronous endpoint.
-+ */
-+ unsigned ntd:8;
-+
-+ /** Data packets to transfer */
-+ unsigned reserved16_28:13;
-+
-+ /**
-+ * Packet ID for next data packet
-+ * 0: DATA0
-+ * 1: DATA2
-+ * 2: DATA1
-+ * 3: MDATA (non-Control)
-+ */
-+ unsigned pid:2;
-+
-+ /** Do PING protocol when 1 */
-+ unsigned dopng:1;
-+ } b_ddma;
-+} hctsiz_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Host DMA Address
-+ * Register used in Descriptor DMA mode.
-+ */
-+typedef union hcdma_data {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ unsigned reserved0_2:3;
-+ /** Current Transfer Descriptor. Not used for ISOC */
-+ unsigned ctd:8;
-+ /** Start Address of Descriptor List */
-+ unsigned dma_addr:21;
-+ } b;
-+} hcdma_data_t;
-+
-+/**
-+ * This union represents the bit fields in the DMA Descriptor
-+ * status quadlet for host mode. Read the quadlet into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union host_dma_desc_sts {
-+ /** raw register data */
-+ uint32_t d32;
-+ /** quadlet bits */
-+
-+ /* for non-isochronous */
-+ struct {
-+ /** Number of bytes */
-+ unsigned n_bytes:17;
-+ /** QTD offset to jump when Short Packet received - only for IN EPs */
-+ unsigned qtd_offset:6;
-+ /**
-+ * Set to request the core to jump to alternate QTD if
-+ * Short Packet received - only for IN EPs
-+ */
-+ unsigned a_qtd:1;
-+ /**
-+ * Setup Packet bit. When set indicates that buffer contains
-+ * setup packet.
-+ */
-+ unsigned sup:1;
-+ /** Interrupt On Complete */
-+ unsigned ioc:1;
-+ /** End of List */
-+ unsigned eol:1;
-+ unsigned reserved27:1;
-+ /** Rx/Tx Status */
-+ unsigned sts:2;
-+#define DMA_DESC_STS_PKTERR 1
-+ unsigned reserved30:1;
-+ /** Active Bit */
-+ unsigned a:1;
-+ } b;
-+ /* for isochronous */
-+ struct {
-+ /** Number of bytes */
-+ unsigned n_bytes:12;
-+ unsigned reserved12_24:13;
-+ /** Interrupt On Complete */
-+ unsigned ioc:1;
-+ unsigned reserved26_27:2;
-+ /** Rx/Tx Status */
-+ unsigned sts:2;
-+ unsigned reserved30:1;
-+ /** Active Bit */
-+ unsigned a:1;
-+ } b_isoc;
-+} host_dma_desc_sts_t;
-+
-+#define MAX_DMA_DESC_SIZE 131071
-+#define MAX_DMA_DESC_NUM_GENERIC 64
-+#define MAX_DMA_DESC_NUM_HS_ISOC 256
-+#define MAX_FRLIST_EN_NUM 64
-+/**
-+ * Host-mode DMA Descriptor structure
-+ *
-+ * DMA Descriptor structure contains two quadlets:
-+ * Status quadlet and Data buffer pointer.
-+ */
-+typedef struct dwc_otg_host_dma_desc {
-+ /** DMA Descriptor status quadlet */
-+ host_dma_desc_sts_t status;
-+ /** DMA Descriptor data buffer pointer */
-+ uint32_t buf;
-+} dwc_otg_host_dma_desc_t;
-+
-+/** OTG Host Interface Structure.
-+ *
-+ * The OTG Host Interface Structure structure contains information
-+ * needed to manage the DWC_otg controller acting in host mode. It
-+ * represents the programming view of the host-specific aspects of the
-+ * controller.
-+ */
-+typedef struct dwc_otg_host_if {
-+ /** Host Global Registers starting at offset 400h.*/
-+ dwc_otg_host_global_regs_t *host_global_regs;
-+#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
-+
-+ /** Host Port 0 Control and Status Register */
-+ volatile uint32_t *hprt0;
-+#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
-+
-+ /** Host Channel Specific Registers at offsets 500h-5FCh. */
-+ dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
-+#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
-+#define DWC_OTG_CHAN_REGS_OFFSET 0x20
-+
-+ /* Host configuration information */
-+ /** Number of Host Channels (range: 1-16) */
-+ uint8_t num_host_channels;
-+ /** Periodic EPs supported (0: no, 1: yes) */
-+ uint8_t perio_eps_supported;
-+ /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
-+ uint16_t perio_tx_fifo_size;
-+
-+} dwc_otg_host_if_t;
-+
-+/**
-+ * This union represents the bit fields in the Power and Clock Gating Control
-+ * Register. Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union pcgcctl_data {
-+ /** raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ /** Stop Pclk */
-+ unsigned stoppclk:1;
-+ /** Gate Hclk */
-+ unsigned gatehclk:1;
-+ /** Power Clamp */
-+ unsigned pwrclmp:1;
-+ /** Reset Power Down Modules */
-+ unsigned rstpdwnmodule:1;
-+ /** Reserved */
-+ unsigned reserved:1;
-+ /** Enable Sleep Clock Gating (Enbl_L1Gating) */
-+ unsigned enbl_sleep_gating:1;
-+ /** PHY In Sleep (PhySleep) */
-+ unsigned phy_in_sleep:1;
-+ /** Deep Sleep*/
-+ unsigned deep_sleep:1;
-+ unsigned resetaftsusp:1;
-+ unsigned restoremode:1;
-+ unsigned enbl_extnd_hiber:1;
-+ unsigned extnd_hiber_pwrclmp:1;
-+ unsigned extnd_hiber_switch:1;
-+ unsigned ess_reg_restored:1;
-+ unsigned prt_clk_sel:2;
-+ unsigned port_power:1;
-+ unsigned max_xcvrselect:2;
-+ unsigned max_termsel:1;
-+ unsigned mac_dev_addr:7;
-+ unsigned p2hd_dev_enum_spd:2;
-+ unsigned p2hd_prt_spd:2;
-+ unsigned if_dev_mode:1;
-+ } b;
-+} pcgcctl_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Global Data FIFO Software
-+ * Configuration Register. Read the register into the <i>d32</i> member then
-+ * set/clear the bits using the <i>b</i>it elements.
-+ */
-+typedef union gdfifocfg_data {
-+ /* raw register data */
-+ uint32_t d32;
-+ /** register bits */
-+ struct {
-+ /** OTG Data FIFO depth */
-+ unsigned gdfifocfg:16;
-+ /** Start address of EP info controller */
-+ unsigned epinfobase:16;
-+ } b;
-+} gdfifocfg_data_t;
-+
-+/**
-+ * This union represents the bit fields in the Global Power Down Register
-+ * Register. Read the register into the <i>d32</i> member then set/clear the
-+ * bits using the <i>b</i>it elements.
-+ */
-+typedef union gpwrdn_data {
-+ /* raw register data */
-+ uint32_t d32;
-+
-+ /** register bits */
-+ struct {
-+ /** PMU Interrupt Select */
-+ unsigned pmuintsel:1;
-+ /** PMU Active */
-+ unsigned pmuactv:1;
-+ /** Restore */
-+ unsigned restore:1;
-+ /** Power Down Clamp */
-+ unsigned pwrdnclmp:1;
-+ /** Power Down Reset */
-+ unsigned pwrdnrstn:1;
-+ /** Power Down Switch */
-+ unsigned pwrdnswtch:1;
-+ /** Disable VBUS */
-+ unsigned dis_vbus:1;
-+ /** Line State Change */
-+ unsigned lnstschng:1;
-+ /** Line state change mask */
-+ unsigned lnstchng_msk:1;
-+ /** Reset Detected */
-+ unsigned rst_det:1;
-+ /** Reset Detect mask */
-+ unsigned rst_det_msk:1;
-+ /** Disconnect Detected */
-+ unsigned disconn_det:1;
-+ /** Disconnect Detect mask */
-+ unsigned disconn_det_msk:1;
-+ /** Connect Detected*/
-+ unsigned connect_det:1;
-+ /** Connect Detected Mask*/
-+ unsigned connect_det_msk:1;
-+ /** SRP Detected */
-+ unsigned srp_det:1;
-+ /** SRP Detect mask */
-+ unsigned srp_det_msk:1;
-+ /** Status Change Interrupt */
-+ unsigned sts_chngint:1;
-+ /** Status Change Interrupt Mask */
-+ unsigned sts_chngint_msk:1;
-+ /** Line State */
-+ unsigned linestate:2;
-+ /** Indicates current mode(status of IDDIG signal) */
-+ unsigned idsts:1;
-+ /** B Session Valid signal status*/
-+ unsigned bsessvld:1;
-+ /** ADP Event Detected */
-+ unsigned adp_int:1;
-+ /** Multi Valued ID pin */
-+ unsigned mult_val_id_bc:5;
-+ /** Reserved 24_31 */
-+ unsigned reserved29_31:3;
-+ } b;
-+} gpwrdn_data_t;
-+
-+#endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/Makefile linux-3.11.10/drivers/usb/host/dwc_otg/Makefile
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,81 @@
-+#
-+# Makefile for DWC_otg Highspeed USB controller driver
-+#
-+
-+ifneq ($(KERNELRELEASE),)
-+
-+# Use the BUS_INTERFACE variable to compile the software for either
-+# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
-+ifeq ($(BUS_INTERFACE),)
-+# BUS_INTERFACE = -DPCI_INTERFACE
-+# BUS_INTERFACE = -DLM_INTERFACE
-+ BUS_INTERFACE = -DPLATFORM_INTERFACE
-+endif
-+
-+#EXTRA_CFLAGS += -DDEBUG
-+#EXTRA_CFLAGS += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
-+
-+# Use one of the following flags to compile the software in host-only or
-+# device-only mode.
-+#EXTRA_CFLAGS += -DDWC_HOST_ONLY
-+#EXTRA_CFLAGS += -DDWC_DEVICE_ONLY
-+
-+EXTRA_CFLAGS += -Dlinux -DDWC_HS_ELECT_TST
-+#EXTRA_CFLAGS += -DDWC_EN_ISOC
-+EXTRA_CFLAGS += -I$(obj)/../dwc_common_port
-+#EXTRA_CFLAGS += -I$(PORTLIB)
-+EXTRA_CFLAGS += -DDWC_LINUX
-+EXTRA_CFLAGS += $(CFI)
-+EXTRA_CFLAGS += $(BUS_INTERFACE)
-+#EXTRA_CFLAGS += -DDWC_DEV_SRPCAP
-+
-+obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
-+
-+dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
-+dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
-+dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
-+dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o
-+dwc_otg-objs += dwc_otg_adp.o
-+dwc_otg-objs += dwc_otg_mphi_fix.o
-+ifneq ($(CFI),)
-+dwc_otg-objs += dwc_otg_cfi.o
-+endif
-+
-+kernrelwd := $(subst ., ,$(KERNELRELEASE))
-+kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
-+
-+ifneq ($(kernrel3),2.6.20)
-+EXTRA_CFLAGS += $(CPPFLAGS)
-+endif
-+
-+else
-+
-+PWD := $(shell pwd)
-+PORTLIB := $(PWD)/../dwc_common_port
-+
-+# Command paths
-+CTAGS := $(CTAGS)
-+DOXYGEN := $(DOXYGEN)
-+
-+default: portlib
-+ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
-+
-+install: default
-+ $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
-+ $(MAKE) -C$(KDIR) M=$(PWD) modules_install
-+
-+portlib:
-+ $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
-+ cp $(PORTLIB)/Module.symvers $(PWD)/
-+
-+docs: $(wildcard *.[hc]) doc/doxygen.cfg
-+ $(DOXYGEN) doc/doxygen.cfg
-+
-+tags: $(wildcard *.[hc])
-+ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
-+
-+
-+clean:
-+ rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
-+
-+endif
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm linux-3.11.10/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,337 @@
-+package dwc_otg_test;
-+
-+use strict;
-+use Exporter ();
-+
-+use vars qw(@ISA @EXPORT
-+$sysfsdir $paramdir $errors $params
-+);
-+
-+@ISA = qw(Exporter);
-+
-+#
-+# Globals
-+#
-+$sysfsdir = "/sys/devices/lm0";
-+$paramdir = "/sys/module/dwc_otg";
-+$errors = 0;
-+
-+$params = [
-+ {
-+ NAME => "otg_cap",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 2
-+ },
-+ {
-+ NAME => "dma_enable",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ {
-+ NAME => "dma_burst_size",
-+ DEFAULT => 32,
-+ ENUM => [1, 4, 8, 16, 32, 64, 128, 256],
-+ LOW => 1,
-+ HIGH => 256
-+ },
-+ {
-+ NAME => "host_speed",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ {
-+ NAME => "host_support_fs_ls_low_power",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ {
-+ NAME => "host_ls_low_power_phy_clk",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ {
-+ NAME => "dev_speed",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ {
-+ NAME => "enable_dynamic_fifo",
-+ DEFAULT => 1,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ {
-+ NAME => "data_fifo_size",
-+ DEFAULT => 8192,
-+ ENUM => [],
-+ LOW => 32,
-+ HIGH => 32768
-+ },
-+ {
-+ NAME => "dev_rx_fifo_size",
-+ DEFAULT => 1064,
-+ ENUM => [],
-+ LOW => 16,
-+ HIGH => 32768
-+ },
-+ {
-+ NAME => "dev_nperio_tx_fifo_size",
-+ DEFAULT => 1024,
-+ ENUM => [],
-+ LOW => 16,
-+ HIGH => 32768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_1",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_2",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_3",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_4",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_5",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_6",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_7",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_8",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_9",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_10",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_11",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_12",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_13",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_14",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "dev_perio_tx_fifo_size_15",
-+ DEFAULT => 256,
-+ ENUM => [],
-+ LOW => 4,
-+ HIGH => 768
-+ },
-+ {
-+ NAME => "host_rx_fifo_size",
-+ DEFAULT => 1024,
-+ ENUM => [],
-+ LOW => 16,
-+ HIGH => 32768
-+ },
-+ {
-+ NAME => "host_nperio_tx_fifo_size",
-+ DEFAULT => 1024,
-+ ENUM => [],
-+ LOW => 16,
-+ HIGH => 32768
-+ },
-+ {
-+ NAME => "host_perio_tx_fifo_size",
-+ DEFAULT => 1024,
-+ ENUM => [],
-+ LOW => 16,
-+ HIGH => 32768
-+ },
-+ {
-+ NAME => "max_transfer_size",
-+ DEFAULT => 65535,
-+ ENUM => [],
-+ LOW => 2047,
-+ HIGH => 65535
-+ },
-+ {
-+ NAME => "max_packet_count",
-+ DEFAULT => 511,
-+ ENUM => [],
-+ LOW => 15,
-+ HIGH => 511
-+ },
-+ {
-+ NAME => "host_channels",
-+ DEFAULT => 12,
-+ ENUM => [],
-+ LOW => 1,
-+ HIGH => 16
-+ },
-+ {
-+ NAME => "dev_endpoints",
-+ DEFAULT => 6,
-+ ENUM => [],
-+ LOW => 1,
-+ HIGH => 15
-+ },
-+ {
-+ NAME => "phy_type",
-+ DEFAULT => 1,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 2
-+ },
-+ {
-+ NAME => "phy_utmi_width",
-+ DEFAULT => 16,
-+ ENUM => [8, 16],
-+ LOW => 8,
-+ HIGH => 16
-+ },
-+ {
-+ NAME => "phy_ulpi_ddr",
-+ DEFAULT => 0,
-+ ENUM => [],
-+ LOW => 0,
-+ HIGH => 1
-+ },
-+ ];
-+
-+
-+#
-+#
-+sub check_arch {
-+ $_ = `uname -m`;
-+ chomp;
-+ unless (m/armv4tl/) {
-+ warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n";
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+#
-+#
-+sub load_module {
-+ my $params = shift;
-+ print "\nRemoving Module\n";
-+ system "rmmod dwc_otg";
-+ print "Loading Module\n";
-+ if ($params ne "") {
-+ print "Module Parameters: $params\n";
-+ }
-+ if (system("modprobe dwc_otg $params")) {
-+ warn "Unable to load module\n";
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+#
-+#
-+sub test_status {
-+ my $arg = shift;
-+
-+ print "\n";
-+
-+ if (defined $arg) {
-+ warn "WARNING: $arg\n";
-+ }
-+
-+ if ($errors > 0) {
-+ warn "TEST FAILED with $errors errors\n";
-+ return 0;
-+ } else {
-+ print "TEST PASSED\n";
-+ return 0 if (defined $arg);
-+ }
-+ return 1;
-+}
-+
-+#
-+#
-+@EXPORT = qw(
-+$sysfsdir
-+$paramdir
-+$params
-+$errors
-+check_arch
-+load_module
-+test_status
-+);
-+
-+1;
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/Makefile linux-3.11.10/drivers/usb/host/dwc_otg/test/Makefile
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/test/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,16 @@
-+
-+PERL=/usr/bin/perl
-+PL_TESTS=test_sysfs.pl test_mod_param.pl
-+
-+.PHONY : test
-+test : perl_tests
-+
-+perl_tests :
-+ @echo
-+ @echo Running perl tests
-+ @for test in $(PL_TESTS); do \
-+ if $(PERL) ./$$test ; then \
-+ echo "=======> $$test, PASSED" ; \
-+ else echo "=======> $$test, FAILED" ; \
-+ fi \
-+ done
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/test_mod_param.pl linux-3.11.10/drivers/usb/host/dwc_otg/test/test_mod_param.pl
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/test_mod_param.pl 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/test/test_mod_param.pl 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,133 @@
-+#!/usr/bin/perl -w
-+#
-+# Run this program on the integrator.
-+#
-+# - Tests module parameter default values.
-+# - Tests setting of valid module parameter values via modprobe.
-+# - Tests invalid module parameter values.
-+# -----------------------------------------------------------------------------
-+use strict;
-+use dwc_otg_test;
-+
-+check_arch() or die;
-+
-+#
-+#
-+sub test {
-+ my ($param,$expected) = @_;
-+ my $value = get($param);
-+
-+ if ($value == $expected) {
-+ print "$param = $value, okay\n";
-+ }
-+
-+ else {
-+ warn "ERROR: value of $param != $expected, $value\n";
-+ $errors ++;
-+ }
-+}
-+
-+#
-+#
-+sub get {
-+ my $param = shift;
-+ my $tmp = `cat $paramdir/$param`;
-+ chomp $tmp;
-+ return $tmp;
-+}
-+
-+#
-+#
-+sub test_main {
-+
-+ print "\nTesting Module Parameters\n";
-+
-+ load_module("") or die;
-+
-+ # Test initial values
-+ print "\nTesting Default Values\n";
-+ foreach (@{$params}) {
-+ test ($_->{NAME}, $_->{DEFAULT});
-+ }
-+
-+ # Test low value
-+ print "\nTesting Low Value\n";
-+ my $cmd_params = "";
-+ foreach (@{$params}) {
-+ $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} ";
-+ }
-+ load_module($cmd_params) or die;
-+
-+ foreach (@{$params}) {
-+ test ($_->{NAME}, $_->{LOW});
-+ }
-+
-+ # Test high value
-+ print "\nTesting High Value\n";
-+ $cmd_params = "";
-+ foreach (@{$params}) {
-+ $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} ";
-+ }
-+ load_module($cmd_params) or die;
-+
-+ foreach (@{$params}) {
-+ test ($_->{NAME}, $_->{HIGH});
-+ }
-+
-+ # Test Enum
-+ print "\nTesting Enumerated\n";
-+ foreach (@{$params}) {
-+ if (defined $_->{ENUM}) {
-+ my $value;
-+ foreach $value (@{$_->{ENUM}}) {
-+ $cmd_params = "$_->{NAME}=$value";
-+ load_module($cmd_params) or die;
-+ test ($_->{NAME}, $value);
-+ }
-+ }
-+ }
-+
-+ # Test Invalid Values
-+ print "\nTesting Invalid Values\n";
-+ $cmd_params = "";
-+ foreach (@{$params}) {
-+ $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1;
-+ }
-+ load_module($cmd_params) or die;
-+
-+ foreach (@{$params}) {
-+ test ($_->{NAME}, $_->{DEFAULT});
-+ }
-+
-+ $cmd_params = "";
-+ foreach (@{$params}) {
-+ $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1;
-+ }
-+ load_module($cmd_params) or die;
-+
-+ foreach (@{$params}) {
-+ test ($_->{NAME}, $_->{DEFAULT});
-+ }
-+
-+ print "\nTesting Enumerated\n";
-+ foreach (@{$params}) {
-+ if (defined $_->{ENUM}) {
-+ my $value;
-+ foreach $value (@{$_->{ENUM}}) {
-+ $value = $value + 1;
-+ $cmd_params = "$_->{NAME}=$value";
-+ load_module($cmd_params) or die;
-+ test ($_->{NAME}, $_->{DEFAULT});
-+ $value = $value - 2;
-+ $cmd_params = "$_->{NAME}=$value";
-+ load_module($cmd_params) or die;
-+ test ($_->{NAME}, $_->{DEFAULT});
-+ }
-+ }
-+ }
-+
-+ test_status() or die;
-+}
-+
-+test_main();
-+0;
-diff -Nur linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/test_sysfs.pl linux-3.11.10/drivers/usb/host/dwc_otg/test/test_sysfs.pl
---- linux-3.11.10.orig/drivers/usb/host/dwc_otg/test/test_sysfs.pl 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/dwc_otg/test/test_sysfs.pl 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,193 @@
-+#!/usr/bin/perl -w
-+#
-+# Run this program on the integrator
-+# - Tests select sysfs attributes.
-+# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc.
-+# -----------------------------------------------------------------------------
-+use strict;
-+use dwc_otg_test;
-+
-+check_arch() or die;
-+
-+#
-+#
-+sub test {
-+ my ($attr,$expected) = @_;
-+ my $string = get($attr);
-+
-+ if ($string eq $expected) {
-+ printf("$attr = $string, okay\n");
-+ }
-+ else {
-+ warn "ERROR: value of $attr != $expected, $string\n";
-+ $errors ++;
-+ }
-+}
-+
-+#
-+#
-+sub set {
-+ my ($reg, $value) = @_;
-+ system "echo $value > $sysfsdir/$reg";
-+}
-+
-+#
-+#
-+sub get {
-+ my $attr = shift;
-+ my $string = `cat $sysfsdir/$attr`;
-+ chomp $string;
-+ if ($string =~ m/\s\=\s/) {
-+ my $tmp;
-+ ($tmp, $string) = split /\s=\s/, $string;
-+ }
-+ return $string;
-+}
-+
-+#
-+#
-+sub test_main {
-+ print("\nTesting Sysfs Attributes\n");
-+
-+ load_module("") or die;
-+
-+ # Test initial values of regoffset/regvalue/guid/gsnpsid
-+ print("\nTesting Default Values\n");
-+
-+ test("regoffset", "0xffffffff");
-+ test("regvalue", "invalid offset");
-+ test("guid", "0x12345678"); # this will fail if it has been changed
-+ test("gsnpsid", "0x4f54200a");
-+
-+ # Test operation of regoffset/regvalue
-+ print("\nTesting regoffset\n");
-+ set('regoffset', '5a5a5a5a');
-+ test("regoffset", "0xffffffff");
-+
-+ set('regoffset', '0');
-+ test("regoffset", "0x00000000");
-+
-+ set('regoffset', '40000');
-+ test("regoffset", "0x00000000");
-+
-+ set('regoffset', '3ffff');
-+ test("regoffset", "0x0003ffff");
-+
-+ set('regoffset', '1');
-+ test("regoffset", "0x00000001");
-+
-+ print("\nTesting regvalue\n");
-+ set('regoffset', '3c');
-+ test("regvalue", "0x12345678");
-+ set('regvalue', '5a5a5a5a');
-+ test("regvalue", "0x5a5a5a5a");
-+ set('regvalue','a5a5a5a5');
-+ test("regvalue", "0xa5a5a5a5");
-+ set('guid','12345678');
-+
-+ # Test HNP Capable
-+ print("\nTesting HNP Capable bit\n");
-+ set('hnpcapable', '1');
-+ test("hnpcapable", "0x1");
-+ set('hnpcapable','0');
-+ test("hnpcapable", "0x0");
-+
-+ set('regoffset','0c');
-+
-+ my $old = get('gusbcfg');
-+ print("setting hnpcapable\n");
-+ set('hnpcapable', '1');
-+ test("hnpcapable", "0x1");
-+ test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9)));
-+ test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9)));
-+
-+ $old = get('gusbcfg');
-+ print("clearing hnpcapable\n");
-+ set('hnpcapable', '0');
-+ test("hnpcapable", "0x0");
-+ test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9)));
-+ test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9)));
-+
-+ # Test SRP Capable
-+ print("\nTesting SRP Capable bit\n");
-+ set('srpcapable', '1');
-+ test("srpcapable", "0x1");
-+ set('srpcapable','0');
-+ test("srpcapable", "0x0");
-+
-+ set('regoffset','0c');
-+
-+ $old = get('gusbcfg');
-+ print("setting srpcapable\n");
-+ set('srpcapable', '1');
-+ test("srpcapable", "0x1");
-+ test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8)));
-+ test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8)));
-+
-+ $old = get('gusbcfg');
-+ print("clearing srpcapable\n");
-+ set('srpcapable', '0');
-+ test("srpcapable", "0x0");
-+ test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8)));
-+ test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8)));
-+
-+ # Test GGPIO
-+ print("\nTesting GGPIO\n");
-+ set('ggpio','5a5a5a5a');
-+ test('ggpio','0x5a5a0000');
-+ set('ggpio','a5a5a5a5');
-+ test('ggpio','0xa5a50000');
-+ set('ggpio','11110000');
-+ test('ggpio','0x11110000');
-+ set('ggpio','00001111');
-+ test('ggpio','0x00000000');
-+
-+ # Test DEVSPEED
-+ print("\nTesting DEVSPEED\n");
-+ set('regoffset','800');
-+ $old = get('regvalue');
-+ set('devspeed','0');
-+ test('devspeed','0x0');
-+ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
-+ set('devspeed','1');
-+ test('devspeed','0x1');
-+ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
-+ set('devspeed','2');
-+ test('devspeed','0x2');
-+ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2));
-+ set('devspeed','3');
-+ test('devspeed','0x3');
-+ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3));
-+ set('devspeed','4');
-+ test('devspeed','0x0');
-+ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3)));
-+ set('devspeed','5');
-+ test('devspeed','0x1');
-+ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1));
-+
-+
-+ # mode Returns the current mode:0 for device mode1 for host mode Read
-+ # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write
-+ # srp Initiate the Session Request Protocol. Read returns the status. Read/Write
-+ # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write
-+ # bussuspend Suspend the USB bus. Read/Write
-+ # busconnected Get the connection status of the bus Read
-+
-+ # gotgctl Get or set the Core Control Status Register. Read/Write
-+ ## gusbcfg Get or set the Core USB Configuration Register Read/Write
-+ # grxfsiz Get or set the Receive FIFO Size Register Read/Write
-+ # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write
-+ # gpvndctl Get or set the PHY Vendor Control Register Read/Write
-+ ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write
-+ ## guid Get or set the value of the User ID Register Read/Write
-+ ## gsnpsid Get the value of the Synopsys ID Regester Read
-+ ## devspeed Get or set the device speed setting in the DCFG register Read/Write
-+ # enumspeed Gets the device enumeration Speed. Read
-+ # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read
-+ # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write
-+
-+ test_status("TEST NYI") or die;
-+}
-+
-+test_main();
-+0;
-diff -Nur linux-3.11.10.orig/drivers/usb/host/Kconfig linux-3.11.10/drivers/usb/host/Kconfig
---- linux-3.11.10.orig/drivers/usb/host/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/Kconfig 2014-02-07 19:57:30.000000000 +0100
-@@ -671,6 +671,19 @@
- To compile this driver a module, choose M here: the module
- will be called "hwa-hc".
-
-+config USB_DWCOTG
-+ tristate "Synopsis DWC host support"
-+ depends on USB
-+ help
-+ The Synopsis DWC controller is a dual-role
-+ host/peripheral/OTG ("On The Go") USB controllers.
-+
-+ Enable this option to support this IP in host controller mode.
-+ If unsure, say N.
-+
-+ To compile this driver as a module, choose M here: the
-+ modules built will be called dwc_otg and dwc_common_port.
-+
- config USB_IMX21_HCD
- tristate "i.MX21 HCD support"
- depends on ARM && ARCH_MXC
-diff -Nur linux-3.11.10.orig/drivers/usb/host/Makefile linux-3.11.10/drivers/usb/host/Makefile
---- linux-3.11.10.orig/drivers/usb/host/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/usb/host/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -52,6 +52,8 @@
- obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
- obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
- obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
-+
-+obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
- obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
- obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
- obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
-diff -Nur linux-3.11.10.orig/drivers/usb/Makefile linux-3.11.10/drivers/usb/Makefile
---- linux-3.11.10.orig/drivers/usb/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/usb/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -23,6 +23,7 @@
- obj-$(CONFIG_USB_R8A66597_HCD) += host/
- obj-$(CONFIG_USB_HWA_HCD) += host/
- obj-$(CONFIG_USB_ISP1760_HCD) += host/
-+obj-$(CONFIG_USB_DWCOTG) += host/
- obj-$(CONFIG_USB_IMX21_HCD) += host/
- obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
- obj-$(CONFIG_USB_FUSBH200_HCD) += host/
-diff -Nur linux-3.11.10.orig/drivers/video/bcm2708_fb.c linux-3.11.10/drivers/video/bcm2708_fb.c
---- linux-3.11.10.orig/drivers/video/bcm2708_fb.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/video/bcm2708_fb.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,647 @@
-+/*
-+ * linux/drivers/video/bcm2708_fb.c
-+ *
-+ * Copyright (C) 2010 Broadcom
-+ *
-+ * 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.
-+ *
-+ * Broadcom simple framebuffer driver
-+ *
-+ * This file is derived from cirrusfb.c
-+ * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
-+ *
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/slab.h>
-+#include <linux/mm.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/ioport.h>
-+#include <linux/list.h>
-+#include <linux/platform_device.h>
-+#include <linux/clk.h>
-+#include <linux/printk.h>
-+#include <linux/console.h>
-+
-+#include <mach/dma.h>
-+#include <mach/platform.h>
-+#include <mach/vcio.h>
-+
-+#include <asm/sizes.h>
-+#include <linux/io.h>
-+#include <linux/dma-mapping.h>
-+
-+#ifdef BCM2708_FB_DEBUG
-+#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
-+#else
-+#define print_debug(fmt,...)
-+#endif
-+
-+/* This is limited to 16 characters when displayed by X startup */
-+static const char *bcm2708_name = "BCM2708 FB";
-+
-+#define DRIVER_NAME "bcm2708_fb"
-+
-+/* this data structure describes each frame buffer device we find */
-+
-+struct fbinfo_s {
-+ u32 xres, yres, xres_virtual, yres_virtual;
-+ u32 pitch, bpp;
-+ u32 xoffset, yoffset;
-+ u32 base;
-+ u32 screen_size;
-+ u16 cmap[256];
-+};
-+
-+struct bcm2708_fb {
-+ struct fb_info fb;
-+ struct platform_device *dev;
-+ struct fbinfo_s *info;
-+ dma_addr_t dma;
-+ u32 cmap[16];
-+ int dma_chan;
-+ int dma_irq;
-+ void __iomem *dma_chan_base;
-+ void *cb_base; /* DMA control blocks */
-+ dma_addr_t cb_handle;
-+};
-+
-+#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
-+
-+static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
-+{
-+ int ret = 0;
-+
-+ memset(&var->transp, 0, sizeof(var->transp));
-+
-+ var->red.msb_right = 0;
-+ var->green.msb_right = 0;
-+ var->blue.msb_right = 0;
-+
-+ switch (var->bits_per_pixel) {
-+ case 1:
-+ case 2:
-+ case 4:
-+ case 8:
-+ var->red.length = var->bits_per_pixel;
-+ var->red.offset = 0;
-+ var->green.length = var->bits_per_pixel;
-+ var->green.offset = 0;
-+ var->blue.length = var->bits_per_pixel;
-+ var->blue.offset = 0;
-+ break;
-+ case 16:
-+ var->red.length = 5;
-+ var->blue.length = 5;
-+ /*
-+ * Green length can be 5 or 6 depending whether
-+ * we're operating in RGB555 or RGB565 mode.
-+ */
-+ if (var->green.length != 5 && var->green.length != 6)
-+ var->green.length = 6;
-+ break;
-+ case 24:
-+ var->red.length = 8;
-+ var->blue.length = 8;
-+ var->green.length = 8;
-+ break;
-+ case 32:
-+ var->red.length = 8;
-+ var->green.length = 8;
-+ var->blue.length = 8;
-+ var->transp.length = 8;
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ /*
-+ * >= 16bpp displays have separate colour component bitfields
-+ * encoded in the pixel data. Calculate their position from
-+ * the bitfield length defined above.
-+ */
-+ if (ret == 0 && var->bits_per_pixel >= 24) {
-+ var->red.offset = 0;
-+ var->green.offset = var->red.offset + var->red.length;
-+ var->blue.offset = var->green.offset + var->green.length;
-+ var->transp.offset = var->blue.offset + var->blue.length;
-+ } else if (ret == 0 && var->bits_per_pixel >= 16) {
-+ var->blue.offset = 0;
-+ var->green.offset = var->blue.offset + var->blue.length;
-+ var->red.offset = var->green.offset + var->green.length;
-+ var->transp.offset = var->red.offset + var->red.length;
-+ }
-+
-+ return ret;
-+}
-+
-+static int bcm2708_fb_check_var(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ /* info input, var output */
-+ int yres;
-+
-+ /* info input, var output */
-+ print_debug("bcm2708_fb_check_var info(%p) %dx%d (%dx%d), %d, %d\n", info,
-+ info->var.xres, info->var.yres, info->var.xres_virtual,
-+ info->var.yres_virtual, (int)info->screen_size,
-+ info->var.bits_per_pixel);
-+ print_debug("bcm2708_fb_check_var var(%p) %dx%d (%dx%d), %d\n", var,
-+ var->xres, var->yres, var->xres_virtual, var->yres_virtual,
-+ var->bits_per_pixel);
-+
-+ if (!var->bits_per_pixel)
-+ var->bits_per_pixel = 16;
-+
-+ if (bcm2708_fb_set_bitfields(var) != 0) {
-+ pr_err("bcm2708_fb_check_var: invalid bits_per_pixel %d\n",
-+ var->bits_per_pixel);
-+ return -EINVAL;
-+ }
-+
-+
-+ if (var->xres_virtual < var->xres)
-+ var->xres_virtual = var->xres;
-+ /* use highest possible virtual resolution */
-+ if (var->yres_virtual == -1) {
-+ var->yres_virtual = 480;
-+
-+ pr_err
-+ ("bcm2708_fb_check_var: virtual resolution set to maximum of %dx%d\n",
-+ var->xres_virtual, var->yres_virtual);
-+ }
-+ if (var->yres_virtual < var->yres)
-+ var->yres_virtual = var->yres;
-+
-+ if (var->xoffset < 0)
-+ var->xoffset = 0;
-+ if (var->yoffset < 0)
-+ var->yoffset = 0;
-+
-+ /* truncate xoffset and yoffset to maximum if too high */
-+ if (var->xoffset > var->xres_virtual - var->xres)
-+ var->xoffset = var->xres_virtual - var->xres - 1;
-+ if (var->yoffset > var->yres_virtual - var->yres)
-+ var->yoffset = var->yres_virtual - var->yres - 1;
-+
-+ yres = var->yres;
-+ if (var->vmode & FB_VMODE_DOUBLE)
-+ yres *= 2;
-+ else if (var->vmode & FB_VMODE_INTERLACED)
-+ yres = (yres + 1) / 2;
-+
-+ if (yres > 1200) {
-+ pr_err("bcm2708_fb_check_var: ERROR: VerticalTotal >= 1200; "
-+ "special treatment required! (TODO)\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int bcm2708_fb_set_par(struct fb_info *info)
-+{
-+ uint32_t val = 0;
-+ struct bcm2708_fb *fb = to_bcm2708(info);
-+ volatile struct fbinfo_s *fbinfo = fb->info;
-+ fbinfo->xres = info->var.xres;
-+ fbinfo->yres = info->var.yres;
-+ fbinfo->xres_virtual = info->var.xres_virtual;
-+ fbinfo->yres_virtual = info->var.yres_virtual;
-+ fbinfo->bpp = info->var.bits_per_pixel;
-+ fbinfo->xoffset = info->var.xoffset;
-+ fbinfo->yoffset = info->var.yoffset;
-+ fbinfo->base = 0; /* filled in by VC */
-+ fbinfo->pitch = 0; /* filled in by VC */
-+
-+ print_debug("bcm2708_fb_set_par info(%p) %dx%d (%dx%d), %d, %d\n", info,
-+ info->var.xres, info->var.yres, info->var.xres_virtual,
-+ info->var.yres_virtual, (int)info->screen_size,
-+ info->var.bits_per_pixel);
-+
-+ /* ensure last write to fbinfo is visible to GPU */
-+ wmb();
-+
-+ /* inform vc about new framebuffer */
-+ bcm_mailbox_write(MBOX_CHAN_FB, fb->dma);
-+
-+ /* TODO: replace fb driver with vchiq version */
-+ /* wait for response */
-+ bcm_mailbox_read(MBOX_CHAN_FB, &val);
-+
-+ /* ensure GPU writes are visible to us */
-+ rmb();
-+
-+ if (val == 0) {
-+ fb->fb.fix.line_length = fbinfo->pitch;
-+
-+ if (info->var.bits_per_pixel <= 8)
-+ fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
-+ else
-+ fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-+
-+ fb->fb.fix.smem_start = fbinfo->base;
-+ fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual;
-+ fb->fb.screen_size = fbinfo->screen_size;
-+ if (fb->fb.screen_base)
-+ iounmap(fb->fb.screen_base);
-+ fb->fb.screen_base =
-+ (void *)ioremap_wc(fb->fb.fix.smem_start, fb->fb.screen_size);
-+ if (!fb->fb.screen_base) {
-+ /* the console may currently be locked */
-+ console_trylock();
-+ console_unlock();
-+
-+ BUG(); /* what can we do here */
-+ }
-+ }
-+ print_debug
-+ ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n",
-+ (void *)fb->fb.screen_base, (void *)fb->fb.fix.smem_start,
-+ fbinfo->xres, fbinfo->yres, fbinfo->bpp,
-+ fbinfo->pitch, (int)fb->fb.screen_size, val);
-+
-+ return val;
-+}
-+
-+static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
-+{
-+ unsigned int mask = (1 << bf->length) - 1;
-+
-+ return (val >> (16 - bf->length) & mask) << bf->offset;
-+}
-+
-+
-+static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red,
-+ unsigned int green, unsigned int blue,
-+ unsigned int transp, struct fb_info *info)
-+{
-+ struct bcm2708_fb *fb = to_bcm2708(info);
-+
-+ /*print_debug("BCM2708FB: setcolreg %d:(%02x,%02x,%02x,%02x) %x\n", regno, red, green, blue, transp, fb->fb.fix.visual);*/
-+ if (fb->fb.var.bits_per_pixel <= 8) {
-+ if (regno < 256) {
-+ /* blue [0:4], green [5:10], red [11:15] */
-+ fb->info->cmap[regno] = ((red >> (16-5)) & 0x1f) << 11 |
-+ ((green >> (16-6)) & 0x3f) << 5 |
-+ ((blue >> (16-5)) & 0x1f) << 0;
-+ }
-+ /* Hack: we need to tell GPU the palette has changed, but currently bcm2708_fb_set_par takes noticable time when called for every (256) colour */
-+ /* So just call it for what looks like the last colour in a list for now. */
-+ if (regno == 15 || regno == 255)
-+ bcm2708_fb_set_par(info);
-+ } else if (regno < 16) {
-+ fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
-+ convert_bitfield(blue, &fb->fb.var.blue) |
-+ convert_bitfield(green, &fb->fb.var.green) |
-+ convert_bitfield(red, &fb->fb.var.red);
-+ }
-+ return regno > 255;
-+}
-+
-+static int bcm2708_fb_blank(int blank_mode, struct fb_info *info)
-+{
-+ /*print_debug("bcm2708_fb_blank\n"); */
-+ return -1;
-+}
-+
-+static void bcm2708_fb_fillrect(struct fb_info *info,
-+ const struct fb_fillrect *rect)
-+{
-+ /* (is called) print_debug("bcm2708_fb_fillrect\n"); */
-+ cfb_fillrect(info, rect);
-+}
-+
-+/* A helper function for configuring dma control block */
-+static void set_dma_cb(struct bcm2708_dma_cb *cb,
-+ int burst_size,
-+ dma_addr_t dst,
-+ int dst_stride,
-+ dma_addr_t src,
-+ int src_stride,
-+ int w,
-+ int h)
-+{
-+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
-+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
-+ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
-+ cb->dst = dst;
-+ cb->src = src;
-+ /*
-+ * This is not really obvious from the DMA documentation,
-+ * but the top 16 bits must be programmmed to "height -1"
-+ * and not "height" in 2D mode.
-+ */
-+ cb->length = ((h - 1) << 16) | w;
-+ cb->stride = ((dst_stride - w) << 16) | (u16)(src_stride - w);
-+ cb->pad[0] = 0;
-+ cb->pad[1] = 0;
-+}
-+
-+static void bcm2708_fb_copyarea(struct fb_info *info,
-+ const struct fb_copyarea *region)
-+{
-+ struct bcm2708_fb *fb = to_bcm2708(info);
-+ struct bcm2708_dma_cb *cb = fb->cb_base;
-+ int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3;
-+ /* Channel 0 supports larger bursts and is a bit faster */
-+ int burst_size = (fb->dma_chan == 0) ? 8 : 2;
-+
-+ /* Fallback to cfb_copyarea() if we don't like something */
-+ if (bytes_per_pixel > 4 ||
-+ info->var.xres > 1920 || info->var.yres > 1200 ||
-+ region->width <= 0 || region->width > info->var.xres ||
-+ region->height <= 0 || region->height > info->var.yres ||
-+ region->sx < 0 || region->sx >= info->var.xres ||
-+ region->sy < 0 || region->sy >= info->var.yres ||
-+ region->dx < 0 || region->dx >= info->var.xres ||
-+ region->dy < 0 || region->dy >= info->var.yres ||
-+ region->sx + region->width > info->var.xres ||
-+ region->dx + region->width > info->var.xres ||
-+ region->sy + region->height > info->var.yres ||
-+ region->dy + region->height > info->var.yres) {
-+ cfb_copyarea(info, region);
-+ return;
-+ }
-+
-+ if (region->dy == region->sy && region->dx > region->sx) {
-+ /*
-+ * A difficult case of overlapped copy. Because DMA can't
-+ * copy individual scanlines in backwards direction, we need
-+ * two-pass processing. We do it by programming a chain of dma
-+ * control blocks in the first 16K part of the buffer and use
-+ * the remaining 48K as the intermediate temporary scratch
-+ * buffer. The buffer size is sufficient to handle up to
-+ * 1920x1200 resolution at 32bpp pixel depth.
-+ */
-+ int y;
-+ dma_addr_t control_block_pa = fb->cb_handle;
-+ dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024;
-+ int scanline_size = bytes_per_pixel * region->width;
-+ int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size;
-+
-+ for (y = 0; y < region->height; y += scanlines_per_cb) {
-+ dma_addr_t src =
-+ fb->fb.fix.smem_start +
-+ bytes_per_pixel * region->sx +
-+ (region->sy + y) * fb->fb.fix.line_length;
-+ dma_addr_t dst =
-+ fb->fb.fix.smem_start +
-+ bytes_per_pixel * region->dx +
-+ (region->dy + y) * fb->fb.fix.line_length;
-+
-+ if (region->height - y < scanlines_per_cb)
-+ scanlines_per_cb = region->height - y;
-+
-+ set_dma_cb(cb, burst_size, scratchbuf, scanline_size,
-+ src, fb->fb.fix.line_length,
-+ scanline_size, scanlines_per_cb);
-+ control_block_pa += sizeof(struct bcm2708_dma_cb);
-+ cb->next = control_block_pa;
-+ cb++;
-+
-+ set_dma_cb(cb, burst_size, dst, fb->fb.fix.line_length,
-+ scratchbuf, scanline_size,
-+ scanline_size, scanlines_per_cb);
-+ control_block_pa += sizeof(struct bcm2708_dma_cb);
-+ cb->next = control_block_pa;
-+ cb++;
-+ }
-+ /* move the pointer back to the last dma control block */
-+ cb--;
-+ } else {
-+ /* A single dma control block is enough. */
-+ int sy, dy, stride;
-+ if (region->dy <= region->sy) {
-+ /* processing from top to bottom */
-+ dy = region->dy;
-+ sy = region->sy;
-+ stride = fb->fb.fix.line_length;
-+ } else {
-+ /* processing from bottom to top */
-+ dy = region->dy + region->height - 1;
-+ sy = region->sy + region->height - 1;
-+ stride = -fb->fb.fix.line_length;
-+ }
-+ set_dma_cb(cb, burst_size,
-+ fb->fb.fix.smem_start + dy * fb->fb.fix.line_length +
-+ bytes_per_pixel * region->dx,
-+ stride,
-+ fb->fb.fix.smem_start + sy * fb->fb.fix.line_length +
-+ bytes_per_pixel * region->sx,
-+ stride,
-+ region->width * bytes_per_pixel,
-+ region->height);
-+ }
-+
-+ /* end of dma control blocks chain */
-+ cb->next = 0;
-+
-+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
-+ bcm_dma_wait_idle(fb->dma_chan_base);
-+}
-+
-+static void bcm2708_fb_imageblit(struct fb_info *info,
-+ const struct fb_image *image)
-+{
-+ /* (is called) print_debug("bcm2708_fb_imageblit\n"); */
-+ cfb_imageblit(info, image);
-+}
-+
-+static struct fb_ops bcm2708_fb_ops = {
-+ .owner = THIS_MODULE,
-+ .fb_check_var = bcm2708_fb_check_var,
-+ .fb_set_par = bcm2708_fb_set_par,
-+ .fb_setcolreg = bcm2708_fb_setcolreg,
-+ .fb_blank = bcm2708_fb_blank,
-+ .fb_fillrect = bcm2708_fb_fillrect,
-+ .fb_copyarea = bcm2708_fb_copyarea,
-+ .fb_imageblit = bcm2708_fb_imageblit,
-+};
-+
-+static int fbwidth = 800; /* module parameter */
-+static int fbheight = 480; /* module parameter */
-+static int fbdepth = 16; /* module parameter */
-+
-+static int bcm2708_fb_register(struct bcm2708_fb *fb)
-+{
-+ int ret;
-+ dma_addr_t dma;
-+ void *mem;
-+
-+ mem =
-+ dma_alloc_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), &dma,
-+ GFP_KERNEL);
-+
-+ if (NULL == mem) {
-+ pr_err(": unable to allocate fbinfo buffer\n");
-+ ret = -ENOMEM;
-+ } else {
-+ fb->info = (struct fbinfo_s *)mem;
-+ fb->dma = dma;
-+ }
-+ fb->fb.fbops = &bcm2708_fb_ops;
-+ fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA;
-+ fb->fb.pseudo_palette = fb->cmap;
-+
-+ strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id));
-+ fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
-+ fb->fb.fix.type_aux = 0;
-+ fb->fb.fix.xpanstep = 0;
-+ fb->fb.fix.ypanstep = 0;
-+ fb->fb.fix.ywrapstep = 0;
-+ fb->fb.fix.accel = FB_ACCEL_NONE;
-+
-+ fb->fb.var.xres = fbwidth;
-+ fb->fb.var.yres = fbheight;
-+ fb->fb.var.xres_virtual = fbwidth;
-+ fb->fb.var.yres_virtual = fbheight;
-+ fb->fb.var.bits_per_pixel = fbdepth;
-+ fb->fb.var.vmode = FB_VMODE_NONINTERLACED;
-+ fb->fb.var.activate = FB_ACTIVATE_NOW;
-+ fb->fb.var.nonstd = 0;
-+ fb->fb.var.height = -1; /* height of picture in mm */
-+ fb->fb.var.width = -1; /* width of picture in mm */
-+ fb->fb.var.accel_flags = 0;
-+
-+ fb->fb.monspecs.hfmin = 0;
-+ fb->fb.monspecs.hfmax = 100000;
-+ fb->fb.monspecs.vfmin = 0;
-+ fb->fb.monspecs.vfmax = 400;
-+ fb->fb.monspecs.dclkmin = 1000000;
-+ fb->fb.monspecs.dclkmax = 100000000;
-+
-+ bcm2708_fb_set_bitfields(&fb->fb.var);
-+
-+ /*
-+ * Allocate colourmap.
-+ */
-+
-+ fb_set_var(&fb->fb, &fb->fb.var);
-+
-+ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d)\n", fbwidth,
-+ fbheight, fbdepth);
-+
-+ ret = register_framebuffer(&fb->fb);
-+ print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
-+ if (ret == 0)
-+ goto out;
-+
-+ print_debug("BCM2708FB: cannot register framebuffer (%d)\n", ret);
-+out:
-+ return ret;
-+}
-+
-+static int bcm2708_fb_probe(struct platform_device *dev)
-+{
-+ struct bcm2708_fb *fb;
-+ int ret;
-+
-+ fb = kmalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
-+ if (!fb) {
-+ dev_err(&dev->dev,
-+ "could not allocate new bcm2708_fb struct\n");
-+ ret = -ENOMEM;
-+ goto free_region;
-+ }
-+ memset(fb, 0, sizeof(struct bcm2708_fb));
-+
-+ fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
-+ &fb->cb_handle, GFP_KERNEL);
-+ if (!fb->cb_base) {
-+ dev_err(&dev->dev, "cannot allocate DMA CBs\n");
-+ ret = -ENOMEM;
-+ goto free_fb;
-+ }
-+
-+ pr_info("BCM2708FB: allocated DMA memory %08x\n",
-+ fb->cb_handle);
-+
-+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
-+ &fb->dma_chan_base, &fb->dma_irq);
-+ if (ret < 0) {
-+ dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
-+ goto free_cb;
-+ }
-+ fb->dma_chan = ret;
-+
-+ pr_info("BCM2708FB: allocated DMA channel %d @ %p\n",
-+ fb->dma_chan, fb->dma_chan_base);
-+
-+ fb->dev = dev;
-+
-+ ret = bcm2708_fb_register(fb);
-+ if (ret == 0) {
-+ platform_set_drvdata(dev, fb);
-+ goto out;
-+ }
-+
-+free_cb:
-+ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
-+free_fb:
-+ kfree(fb);
-+free_region:
-+ dev_err(&dev->dev, "probe failed, err %d\n", ret);
-+out:
-+ return ret;
-+}
-+
-+static int bcm2708_fb_remove(struct platform_device *dev)
-+{
-+ struct bcm2708_fb *fb = platform_get_drvdata(dev);
-+
-+ platform_set_drvdata(dev, NULL);
-+
-+ if (fb->fb.screen_base)
-+ iounmap(fb->fb.screen_base);
-+ unregister_framebuffer(&fb->fb);
-+
-+ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
-+ bcm_dma_chan_free(fb->dma_chan);
-+
-+ dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info,
-+ fb->dma);
-+ kfree(fb);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm2708_fb_driver = {
-+ .probe = bcm2708_fb_probe,
-+ .remove = bcm2708_fb_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init bcm2708_fb_init(void)
-+{
-+ return platform_driver_register(&bcm2708_fb_driver);
-+}
-+
-+module_init(bcm2708_fb_init);
-+
-+static void __exit bcm2708_fb_exit(void)
-+{
-+ platform_driver_unregister(&bcm2708_fb_driver);
-+}
-+
-+module_exit(bcm2708_fb_exit);
-+
-+module_param(fbwidth, int, 0644);
-+module_param(fbheight, int, 0644);
-+module_param(fbdepth, int, 0644);
-+
-+MODULE_DESCRIPTION("BCM2708 framebuffer driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM_DESC(fbwidth, "Width of ARM Framebuffer");
-+MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer");
-+MODULE_PARM_DESC(fbdepth, "Bit depth of ARM Framebuffer");
-diff -Nur linux-3.11.10.orig/drivers/video/cfbimgblt.c linux-3.11.10/drivers/video/cfbimgblt.c
---- linux-3.11.10.orig/drivers/video/cfbimgblt.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/video/cfbimgblt.c 2014-02-07 19:57:30.000000000 +0100
-@@ -28,6 +28,11 @@
- *
- * Also need to add code to deal with cards endians that are different than
- * the native cpu endians. I also need to deal with MSB position in the word.
-+ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013:
-+ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are
-+ * significantly faster than the previous implementation.
-+ * - Simplify the fast/slow_imageblit selection code, avoiding integer
-+ * divides.
- */
- #include <linux/module.h>
- #include <linux/string.h>
-@@ -262,6 +267,133 @@
- }
- }
-
-+/*
-+ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded
-+ * into the code, main loop unrolled.
-+ */
-+
-+static inline void fast_imageblit16(const struct fb_image *image,
-+ struct fb_info *p, u8 __iomem * dst1,
-+ u32 fgcolor, u32 bgcolor)
-+{
-+ u32 fgx = fgcolor, bgx = bgcolor;
-+ u32 spitch = (image->width + 7) / 8;
-+ u32 end_mask, eorx;
-+ const char *s = image->data, *src;
-+ u32 __iomem *dst;
-+ const u32 *tab = NULL;
-+ int i, j, k;
-+
-+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
-+
-+ fgx <<= 16;
-+ bgx <<= 16;
-+ fgx |= fgcolor;
-+ bgx |= bgcolor;
-+
-+ eorx = fgx ^ bgx;
-+ k = image->width / 2;
-+
-+ for (i = image->height; i--;) {
-+ dst = (u32 __iomem *) dst1;
-+ src = s;
-+
-+ j = k;
-+ while (j >= 4) {
-+ u8 bits = *src;
-+ end_mask = tab[(bits >> 6) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 4) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 2) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[bits & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ src++;
-+ j -= 4;
-+ }
-+ if (j != 0) {
-+ u8 bits = *src;
-+ end_mask = tab[(bits >> 6) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ if (j >= 2) {
-+ end_mask = tab[(bits >> 4) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ if (j == 3) {
-+ end_mask = tab[(bits >> 2) & 3];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
-+ }
-+ }
-+ }
-+ dst1 += p->fix.line_length;
-+ s += spitch;
-+ }
-+}
-+
-+/*
-+ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded
-+ * into the code, main loop unrolled.
-+ */
-+
-+static inline void fast_imageblit32(const struct fb_image *image,
-+ struct fb_info *p, u8 __iomem * dst1,
-+ u32 fgcolor, u32 bgcolor)
-+{
-+ u32 fgx = fgcolor, bgx = bgcolor;
-+ u32 spitch = (image->width + 7) / 8;
-+ u32 end_mask, eorx;
-+ const char *s = image->data, *src;
-+ u32 __iomem *dst;
-+ const u32 *tab = NULL;
-+ int i, j, k;
-+
-+ tab = cfb_tab32;
-+
-+ eorx = fgx ^ bgx;
-+ k = image->width;
-+
-+ for (i = image->height; i--;) {
-+ dst = (u32 __iomem *) dst1;
-+ src = s;
-+
-+ j = k;
-+ while (j >= 8) {
-+ u8 bits = *src;
-+ end_mask = tab[(bits >> 7) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 6) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 5) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 4) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 3) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 2) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[(bits >> 1) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ end_mask = tab[bits & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ src++;
-+ j -= 8;
-+ }
-+ if (j != 0) {
-+ u32 bits = (u32) * src;
-+ while (j > 1) {
-+ end_mask = tab[(bits >> 7) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
-+ bits <<= 1;
-+ j--;
-+ }
-+ end_mask = tab[(bits >> 7) & 1];
-+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
-+ }
-+ dst1 += p->fix.line_length;
-+ s += spitch;
-+ }
-+}
-+
- void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
- {
- u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
-@@ -294,11 +426,21 @@
- bgcolor = image->bg_color;
- }
-
-- if (32 % bpp == 0 && !start_index && !pitch_index &&
-- ((width & (32/bpp-1)) == 0) &&
-- bpp >= 8 && bpp <= 32)
-- fast_imageblit(image, p, dst1, fgcolor, bgcolor);
-- else
-+ if (!start_index && !pitch_index) {
-+ if (bpp == 32)
-+ fast_imageblit32(image, p, dst1, fgcolor,
-+ bgcolor);
-+ else if (bpp == 16 && (width & 1) == 0)
-+ fast_imageblit16(image, p, dst1, fgcolor,
-+ bgcolor);
-+ else if (bpp == 8 && (width & 3) == 0)
-+ fast_imageblit(image, p, dst1, fgcolor,
-+ bgcolor);
-+ else
-+ slow_imageblit(image, p, dst1, fgcolor,
-+ bgcolor,
-+ start_index, pitch_index);
-+ } else
- slow_imageblit(image, p, dst1, fgcolor, bgcolor,
- start_index, pitch_index);
- } else
-diff -Nur linux-3.11.10.orig/drivers/video/fbmem.c linux-3.11.10/drivers/video/fbmem.c
---- linux-3.11.10.orig/drivers/video/fbmem.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/video/fbmem.c 2014-02-07 19:57:30.000000000 +0100
-@@ -1074,6 +1074,25 @@
- return ret;
- }
-
-+static int fb_copyarea_user(struct fb_info *info,
-+ struct fb_copyarea *copy)
-+{
-+ int ret = 0;
-+ if (!lock_fb_info(info))
-+ return -ENODEV;
-+ if (copy->dx + copy->width > info->var.xres ||
-+ copy->sx + copy->width > info->var.xres ||
-+ copy->dy + copy->height > info->var.yres ||
-+ copy->sy + copy->height > info->var.yres) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ info->fbops->fb_copyarea(info, copy);
-+out:
-+ unlock_fb_info(info);
-+ return ret;
-+}
-+
- static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
- {
-@@ -1084,6 +1103,7 @@
- struct fb_cmap cmap_from;
- struct fb_cmap_user cmap;
- struct fb_event event;
-+ struct fb_copyarea copy;
- void __user *argp = (void __user *)arg;
- long ret = 0;
-
-@@ -1193,6 +1213,15 @@
- console_unlock();
- unlock_fb_info(info);
- break;
-+ case FBIOCOPYAREA:
-+ if (info->flags & FBINFO_HWACCEL_COPYAREA) {
-+ /* only provide this ioctl if it is accelerated */
-+ if (copy_from_user(&copy, argp, sizeof(copy)))
-+ return -EFAULT;
-+ ret = fb_copyarea_user(info, &copy);
-+ break;
-+ }
-+ /* fall through */
- default:
- if (!lock_fb_info(info))
- return -ENODEV;
-@@ -1347,6 +1376,7 @@
- case FBIOPAN_DISPLAY:
- case FBIOGET_CON2FBMAP:
- case FBIOPUT_CON2FBMAP:
-+ case FBIOCOPYAREA:
- arg = (unsigned long) compat_ptr(arg);
- case FBIOBLANK:
- ret = do_fb_ioctl(info, cmd, arg);
-diff -Nur linux-3.11.10.orig/drivers/video/Kconfig linux-3.11.10/drivers/video/Kconfig
---- linux-3.11.10.orig/drivers/video/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/video/Kconfig 2014-02-07 19:57:30.000000000 +0100
-@@ -310,6 +310,20 @@
- help
- Support the Permedia2 FIFO disconnect feature.
-
-+config FB_BCM2708
-+ tristate "BCM2708 framebuffer support"
-+ depends on FB && ARM
-+ select FB_CFB_FILLRECT
-+ select FB_CFB_COPYAREA
-+ select FB_CFB_IMAGEBLIT
-+ help
-+ This framebuffer device driver is for the BCM2708 framebuffer.
-+
-+ If you want to compile this as a module (=code which can be
-+ inserted into and removed from the running kernel), say M
-+ here and read <file:Documentation/kbuild/modules.txt>. The module
-+ will be called bcm2708_fb.
-+
- config FB_ARMCLCD
- tristate "ARM PrimeCell PL110 support"
- depends on FB && ARM && ARM_AMBA
-diff -Nur linux-3.11.10.orig/drivers/video/logo/logo_linux_clut224.ppm linux-3.11.10/drivers/video/logo/logo_linux_clut224.ppm
---- linux-3.11.10.orig/drivers/video/logo/logo_linux_clut224.ppm 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/video/logo/logo_linux_clut224.ppm 2014-02-07 19:57:30.000000000 +0100
-@@ -1,883 +1,883 @@
- P3
--80 80
-+63 80
- 255
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 11 15 17 33 49 54 59 85 92 73 97 106
--83 116 129 105 131 142 115 114 122 74 88 93 20 29 31 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 10 10 10 10 10 10
--10 10 10 6 6 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 2 3 3 17 23 26 50 67 72 73 97 106 59 85 92 73 97 106
--105 131 142 124 127 131 105 131 142 105 131 142 53 75 83 6 8 8 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 6 6 6 10 10 10 14 14 14 22 22 22 26 26 26 30 30 30 34 34 34
--30 30 30 30 30 30 26 26 26 18 18 18 14 14 14 10 10 10 6 6 6 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0
--0 0 0 1 1 1 26 35 39 59 85 92 59 85 92 59 85 92 29 43 47 53 75 83
--108 122 132 132 98 104 108 122 132 105 131 142 101 101 101 43 45 48 6 8 8 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--6 6 6 14 14 14 26 26 26 42 42 42 54 54 54 66 66 66 78 78 78 78 78 78
--78 78 78 74 74 74 66 66 66 54 54 54 42 42 42 26 26 26 18 18 18 10 10 10
--6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
--11 15 17 27 40 45 59 85 92 59 85 92 27 40 45 31 45 49 73 97 106 93 121 133
--108 122 132 108 122 132 105 131 142 108 122 132 105 131 142 73 97 106 26 35 39 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--22 22 22 42 42 42 66 66 66 86 86 86 66 66 66 38 38 38 38 38 38 22 22 22
--26 26 26 34 34 34 54 54 54 66 66 66 86 86 86 70 70 70 46 46 46 26 26 26
--14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 7 12 13 21 31 35 42 59 64
--53 75 83 53 75 83 50 67 72 42 59 64 32 40 45 42 59 64 73 97 106 116 116 116
--132 98 104 116 116 116 108 122 132 117 104 110 105 131 142 83 116 129 50 67 72 7 12 13
--1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26
--50 50 50 82 82 82 58 58 58 6 6 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 54 54 54 86 86 86 66 66 66
--38 38 38 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 1 1 1 6 8 8 15 22 25 26 35 39 36 54 60 53 75 83 59 85 92
--59 85 92 48 63 69 15 22 25 12 17 20 52 67 79 94 94 94 132 98 104 132 98 104
--117 104 110 108 122 132 108 122 132 115 114 122 105 131 142 77 105 114 59 85 92 36 54 60
--7 12 13 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50
--78 78 78 34 34 34 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 70 70 70
--78 78 78 46 46 46 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 15 22 25 29 43 47 36 54 60 42 59 64 42 59 64 48 63 69 21 31 35
--6 8 8 29 43 47 36 50 56 43 45 48 79 78 84 132 98 104 165 78 79 132 98 104
--108 122 132 117 104 110 117 104 110 108 122 132 77 105 114 73 97 106 95 131 149 78 102 129
--36 50 56 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 42 42 42 82 82 82
--26 26 26 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 14 14 14 46 46 46 34 34 34 6 6 6 2 2 6
--42 42 42 78 78 78 42 42 42 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--27 40 45 53 75 83 48 63 69 24 31 37 6 8 12 0 0 0 18 25 28 26 35 39
--12 17 20 26 35 39 65 78 84 112 81 86 152 81 83 137 83 86 132 98 104 117 104 110
--117 104 110 132 98 104 132 98 104 115 114 122 73 97 106 53 75 83 95 131 149 93 124 152
--68 78 128 15 22 25 0 0 0 0 0 0 10 10 10 30 30 30 66 66 66 58 58 58
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 26 26 26 86 86 86 101 101 101 46 46 46 10 10 10
--2 2 6 58 58 58 70 70 70 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--36 50 56 21 30 33 4 7 7 0 0 0 1 1 1 17 12 12 69 31 31 68 59 64
--57 59 63 21 31 35 32 40 45 86 73 69 152 81 83 152 81 83 117 104 110 132 98 104
--152 81 83 132 98 104 108 122 132 77 105 114 77 105 114 93 121 133 95 131 149 93 124 152
--95 131 149 53 75 83 11 15 17 0 0 0 14 14 14 42 42 42 86 86 86 10 10 10
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 30 30 30 94 94 94 94 94 94 58 58 58 26 26 26
--2 2 6 6 6 6 78 78 78 54 54 54 22 22 22 6 6 6 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--17 23 26 2 3 3 0 0 0 17 12 12 69 31 31 123 55 55 123 55 55 152 81 83
--86 73 69 17 23 26 7 12 13 45 54 57 101 101 101 137 83 86 132 98 104 132 98 104
--137 83 86 117 104 110 77 105 114 42 59 64 50 67 72 78 102 129 91 117 157 91 117 157
--95 131 149 83 116 129 40 48 73 6 6 6 22 22 22 62 62 62 62 62 62 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 26 26 26 54 54 54 38 38 38 18 18 18 10 10 10
--2 2 6 2 2 6 34 34 34 82 82 82 38 38 38 14 14 14 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--1 1 1 1 2 2 2 3 3 28 12 12 123 55 55 174 79 79 174 79 79 174 79 79
--152 81 83 68 59 64 26 35 39 27 40 45 79 78 84 137 83 86 165 78 79 137 83 86
--94 94 94 48 63 69 36 50 56 50 67 72 73 97 106 93 121 133 93 124 152 93 124 152
--95 131 149 91 118 149 78 102 129 27 40 45 30 30 30 78 78 78 30 30 30 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 10 10 10 10 10 10 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 78 78 78 50 50 50 18 18 18 6 6 6 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--4 5 3 24 53 24 19 31 15 8 7 3 90 61 47 165 78 79 174 79 79 174 79 79
--174 79 79 137 83 86 60 52 57 7 12 13 17 23 26 70 70 70 132 98 104 112 81 86
--79 78 84 31 45 49 15 22 25 53 75 83 91 118 149 86 106 160 91 117 157 93 124 152
--91 117 157 93 124 152 95 131 149 53 75 83 50 50 50 86 86 86 14 14 14 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 54 54 54 66 66 66 26 26 26 6 6 6 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--19 31 15 34 76 34 34 76 34 19 31 15 28 12 12 123 55 55 174 79 79 174 79 79
--174 79 79 165 78 79 112 81 86 32 40 45 15 22 25 38 53 58 65 78 84 29 31 32
--21 30 33 42 59 64 60 80 103 78 102 129 87 112 149 84 96 162 91 117 157 93 124 152
--91 117 157 93 124 152 93 121 133 59 85 92 57 68 71 82 85 86 2 2 6 2 2 6
--2 2 6 6 6 6 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 6 6 6 14 14 14 10 10 10 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 18 18 18 82 82 82 34 34 34 10 10 10 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--34 76 34 40 89 40 40 89 40 34 76 34 8 15 6 48 26 18 123 55 55 174 79 79
--174 79 79 174 79 79 137 83 86 68 59 64 32 40 45 21 30 33 31 45 49 21 31 35
--12 17 20 48 63 69 78 102 129 81 88 166 84 96 162 91 117 157 93 124 152 91 117 157
--93 124 152 95 131 149 83 116 129 59 85 92 57 68 71 86 86 86 2 2 6 2 2 6
--6 6 6 6 6 6 22 22 22 34 34 34 6 6 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 18 18 18 34 34 34 10 10 10 50 50 50 22 22 22 2 2 6
--2 2 6 2 2 6 2 2 6 10 10 10 86 86 86 42 42 42 14 14 14 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--40 89 40 40 89 40 40 89 40 40 89 40 24 53 24 6 6 6 69 31 31 123 55 55
--123 55 55 90 61 47 69 31 31 36 32 33 21 31 35 7 12 13 18 25 28 48 63 69
--60 80 103 68 78 128 84 101 153 84 96 162 84 96 162 91 117 157 91 117 157 84 96 162
--91 117 157 73 97 106 48 63 69 50 67 72 57 59 63 86 86 86 2 2 6 2 2 6
--38 38 38 116 116 116 94 94 94 22 22 22 22 22 22 2 2 6 2 2 6 2 2 6
--14 14 14 86 86 86 124 131 137 170 170 170 151 151 151 38 38 38 26 26 26 6 6 6
--2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 46 46 46 14 14 14 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--34 76 34 40 89 40 40 89 40 40 89 40 34 76 34 19 31 15 17 12 12 48 26 18
--48 26 18 8 7 3 10 10 22 23 29 47 51 61 92 42 59 64 21 30 33 34 45 54
--68 78 128 81 88 166 81 82 173 86 106 160 86 106 160 84 96 162 86 106 160 87 112 149
--91 118 149 77 105 114 52 67 79 32 40 45 50 50 50 86 86 86 2 2 6 14 14 14
--124 131 137 198 198 198 195 195 195 116 116 116 10 10 10 2 2 6 2 2 6 6 6 6
--101 98 89 187 187 187 210 210 210 218 218 218 214 214 214 124 131 137 14 14 14 6 6 6
--2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 50 50 50 18 18 18 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--19 31 15 34 76 34 40 89 40 40 89 40 40 89 40 24 53 24 8 7 3 0 0 0
--6 8 12 28 32 52 51 61 92 54 54 122 74 77 160 68 78 128 26 35 39 6 8 8
--34 45 54 68 78 128 84 96 162 86 106 160 86 106 160 81 88 166 84 96 162 87 112 149
--73 97 106 36 50 56 33 49 54 18 18 18 46 46 46 86 86 86 2 2 6 54 54 54
--218 218 218 195 195 195 226 226 226 246 246 246 58 58 58 2 2 6 2 2 6 30 30 30
--210 210 210 253 253 253 170 170 170 124 127 131 221 221 221 234 234 234 74 74 74 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 22 22 22 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--4 5 3 24 53 24 40 89 40 40 89 40 34 76 34 12 22 15 4 5 3 4 5 3
--13 17 26 54 54 122 78 78 174 78 78 174 78 78 174 74 77 160 51 61 92 21 31 35
--26 35 39 53 75 83 84 101 153 81 82 173 81 88 166 84 101 153 60 80 103 60 80 103
--53 75 83 38 53 58 42 59 64 22 22 22 46 46 46 82 82 82 2 2 6 106 106 106
--170 170 170 26 26 26 86 86 86 226 226 226 124 127 131 10 10 10 14 14 14 46 46 46
--231 231 231 190 190 190 6 6 6 70 70 70 90 90 90 238 238 238 151 151 151 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 22 22 22 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--1 2 2 8 15 6 24 53 24 34 76 34 19 31 15 8 15 6 63 55 20 63 55 20
--18 18 18 40 48 73 74 77 160 78 78 174 78 78 174 81 82 173 74 77 160 52 67 79
--17 23 26 21 31 35 60 80 103 81 88 166 74 77 160 78 102 129 36 54 60 12 17 20
--42 59 64 48 63 69 21 31 35 18 18 18 42 42 42 86 86 86 6 6 6 116 116 116
--106 106 106 6 6 6 70 70 70 151 151 151 124 127 131 18 18 18 38 38 38 54 54 54
--221 221 221 106 106 106 2 2 6 14 14 14 46 46 46 190 190 190 198 198 198 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 22 22 22 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--11 15 17 0 0 0 12 22 15 19 31 15 8 15 6 63 55 20 149 139 69 149 139 69
--63 55 20 10 10 22 54 54 122 78 78 174 78 78 174 78 78 174 81 82 173 68 78 128
--24 31 37 6 6 6 36 50 56 60 80 103 51 61 92 42 59 64 36 50 56 31 45 49
--29 43 47 27 40 45 6 8 8 14 14 14 42 42 42 94 94 94 14 14 14 101 101 101
--124 127 131 2 2 6 18 18 18 116 116 116 106 107 48 121 92 8 121 92 8 98 70 6
--170 170 170 106 106 106 2 2 6 2 2 6 2 2 6 195 195 195 195 195 195 6 6 6
--2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 22 22 22 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--26 35 39 3 5 6 1 1 1 2 3 3 35 31 12 133 118 54 175 176 80 175 176 80
--133 118 54 35 31 12 23 29 47 54 54 122 78 78 174 78 78 174 74 77 160 68 78 128
--51 61 92 31 45 49 26 35 39 36 50 56 29 43 47 7 12 13 21 30 33 42 59 64
--18 25 28 7 12 13 1 1 1 10 10 10 38 38 38 90 90 90 14 14 14 58 58 58
--210 210 210 26 26 26 62 42 6 154 114 10 226 170 11 237 188 10 220 174 15 184 138 11
--220 174 15 174 140 55 35 31 12 2 2 6 70 70 70 246 246 246 124 131 137 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 66 66 66 26 26 26 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--27 40 45 17 23 26 2 3 3 1 1 1 56 77 35 165 152 80 175 176 80 175 176 80
--175 176 80 106 107 48 22 22 22 28 32 52 54 54 122 54 54 122 51 61 92 28 32 52
--20 27 34 31 45 49 11 15 17 7 12 13 36 50 56 31 45 49 29 43 47 36 50 56
--6 8 8 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 14 14 14 10 10 10
--195 195 195 198 179 130 192 133 9 220 174 15 239 182 13 237 188 10 232 195 16 239 207 25
--237 201 50 241 208 19 232 195 16 184 138 11 198 179 130 208 206 196 42 42 42 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 74 74 74 30 30 30 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--15 22 25 26 35 39 15 22 25 0 0 0 35 31 12 133 118 54 175 176 80 175 176 80
--175 176 80 165 152 80 56 77 35 6 8 12 23 29 47 13 17 26 2 2 6 0 0 0
--1 2 2 26 35 39 26 35 39 26 35 39 42 59 64 42 59 64 20 29 31 6 8 8
--0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 86 86 86 14 14 14 2 2 6
--121 92 8 192 133 9 219 162 10 239 182 13 237 188 10 232 195 16 241 208 19 237 201 50
--237 201 50 239 207 25 241 208 19 241 208 19 241 208 19 230 187 11 121 92 8 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 82 82 82 34 34 34 10 10 10
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--1 2 2 15 22 25 31 45 49 6 8 12 4 5 3 63 55 20 149 139 69 175 176 80
--175 176 80 175 176 80 106 107 48 20 16 6 1 1 1 0 0 0 2 3 3 11 15 17
--21 30 33 36 50 56 36 50 56 24 31 37 15 22 25 6 8 8 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 82 82 82 30 30 30 62 42 6
--180 123 7 206 145 10 230 174 11 239 182 13 237 188 10 238 202 15 241 208 19 237 201 50
--239 207 25 241 208 19 241 208 19 241 208 19 230 187 11 220 174 15 184 138 11 6 6 6
--2 2 6 2 2 6 2 2 6 2 2 6 26 26 26 94 94 94 42 42 42 14 14 14
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 1 2 2 29 43 47 26 35 39 3 5 6 8 7 3 106 107 48 165 152 80
--175 176 80 149 139 69 63 55 20 4 5 3 2 3 3 12 17 20 26 35 39 26 35 39
--17 23 26 7 12 13 6 8 8 3 5 6 1 2 2 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 50 50 50 104 69 6
--192 133 9 216 158 10 236 178 12 237 188 10 232 195 16 241 208 19 237 201 50 237 201 50
--241 208 19 241 208 19 241 208 19 204 160 10 200 144 11 216 158 10 156 118 10 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 90 90 90 54 54 54 18 18 18
--6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 12 17 20 27 40 45 18 25 28 1 1 1 35 31 12 106 107 48
--149 139 69 56 77 35 8 7 3 1 2 2 12 17 20 26 35 39 21 31 35 11 15 17
--3 5 6 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 46 46 46 22 22 22
--137 92 6 204 160 10 239 182 13 237 188 10 238 202 15 241 208 19 241 208 19 241 208 19
--241 208 19 204 160 10 184 138 11 210 150 10 216 158 10 210 150 10 98 70 6 2 2 6
--6 6 6 54 54 54 14 14 14 2 2 6 2 2 6 62 62 62 74 74 74 30 30 30
--10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 1 1 1 15 22 25 33 49 54 12 17 20 2 3 3 35 31 12
--56 77 35 20 16 6 1 1 1 18 25 28 21 31 35 11 15 17 1 1 1 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 78 78 78 50 50 50 6 6 6
--88 55 22 139 102 15 190 146 13 230 187 11 239 207 25 232 195 16 220 174 15 190 146 13
--171 120 8 192 133 9 210 150 10 213 154 11 185 146 40 165 152 80 101 98 89 2 2 6
--2 2 6 78 78 78 116 116 116 58 58 58 2 2 6 22 22 22 90 90 90 46 46 46
--18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 1 1 1 27 40 45 29 43 47 3 5 6 2 3 3
--8 7 3 1 1 1 17 23 26 31 45 49 15 22 25 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 50 50 50 6 6 6
--124 127 131 168 158 138 156 107 11 171 120 8 204 160 10 184 138 11 197 138 11 200 144 11
--206 145 10 206 145 10 197 138 11 198 179 130 195 195 195 198 198 198 170 170 170 14 14 14
--2 2 6 22 22 22 116 116 116 116 116 116 22 22 22 2 2 6 74 74 74 70 70 70
--30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 11 15 17 31 45 49 26 35 39 3 5 6
--0 0 0 7 12 13 27 40 45 18 25 28 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 6 6 6 18 18 18 50 50 50 101 101 101 26 26 26 10 10 10
--124 131 137 190 190 190 168 158 138 156 107 11 197 138 11 200 144 11 197 138 11 192 133 9
--180 123 7 185 146 40 198 179 130 187 187 187 202 202 202 221 221 221 214 214 214 66 66 66
--2 2 6 2 2 6 50 50 50 62 62 62 6 6 6 2 2 6 10 10 10 90 90 90
--50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 15 22 25 36 54 60 18 25 28
--0 0 0 21 30 33 27 40 45 2 3 3 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 10 10 10 34 34 34 74 74 74 74 74 74 2 2 6 6 6 6
--151 151 151 198 198 198 190 190 190 168 158 138 148 132 55 156 107 11 156 107 11 169 125 40
--168 158 138 187 187 187 190 190 190 210 210 210 246 246 246 253 253 253 253 253 253 180 180 180
--6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62
--74 74 74 34 34 34 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 27 40 45 35 52 58
--18 25 28 35 52 58 17 23 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 10 10 10 22 22 22 54 54 54 94 94 94 18 18 18 2 2 6 46 46 46
--234 234 234 221 221 221 190 190 190 190 190 190 190 190 190 187 187 187 187 187 187 190 190 190
--190 190 190 195 195 195 214 214 214 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 14 14 14
--86 86 86 54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 12 13 33 49 54
--52 72 81 36 54 60 6 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--6 6 6 18 18 18 46 46 46 90 90 90 46 46 46 18 18 18 6 6 6 180 180 180
--253 253 253 246 246 246 202 202 202 190 190 190 190 190 190 190 190 190 190 190 190 190 190 190
--202 202 202 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--202 202 202 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--42 42 42 86 86 86 42 42 42 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 17 20
--36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--14 14 14 38 38 38 74 74 74 66 66 66 2 2 6 6 6 6 90 90 90 250 250 250
--253 253 253 253 253 253 238 238 238 198 198 198 190 190 190 190 190 190 195 195 195 221 221 221
--246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 78 78 78 70 70 70 34 34 34 14 14 14 6 6 6 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14
--34 34 34 66 66 66 78 78 78 6 6 6 2 2 6 18 18 18 218 218 218 253 253 253
--253 253 253 253 253 253 253 253 253 246 246 246 226 226 226 231 231 231 246 246 246 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 180 180 180 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 18 18 18 90 90 90 62 62 62 30 30 30 10 10 10 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26
--58 58 58 90 90 90 18 18 18 2 2 6 2 2 6 106 106 106 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 231 231 231 18 18 18 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 18 18 18 94 94 94 54 54 54 26 26 26 10 10 10 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50
--90 90 90 26 26 26 2 2 6 2 2 6 14 14 14 195 195 195 250 250 250 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--250 250 250 242 242 242 54 54 54 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 38 38 38 86 86 86 50 50 50 22 22 22 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 38 38 38 82 82 82
--34 34 34 2 2 6 2 2 6 2 2 6 42 42 42 195 195 195 246 246 246 253 253 253
--253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 242 242 242 250 250 250 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 246 246 246 238 238 238
--226 226 226 231 231 231 101 101 101 6 6 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 82 82 82 42 42 42 14 14 14
--6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 62 62 62 66 66 66
--2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 170 170 170 202 202 202 234 234 234
--246 246 246 250 250 250 250 250 250 238 238 238 226 226 226 231 231 231 238 238 238 250 250 250
--250 250 250 250 250 250 246 246 246 231 231 231 214 214 214 202 202 202 202 202 202 202 202 202
--198 198 198 202 202 202 180 180 180 18 18 18 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 66 66 66 30 30 30
--10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 12 17 20 36 54 60 29 43 47 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 82 82 82 18 18 18
--2 2 6 2 2 6 2 2 6 10 10 10 94 94 94 180 180 180 218 218 218 242 242 242
--250 250 250 253 253 253 253 253 253 250 250 250 234 234 234 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 246 246 246 238 238 238 226 226 226 210 210 210 202 202 202
--195 195 195 195 195 195 210 210 210 151 151 151 6 6 6 14 14 14 50 50 50 14 14 14
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 86 86 86 46 46 46
--18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 21 30 33 35 52 58 6 8 12 0 0 0
--0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 54 54 54 70 70 70 2 2 6
--2 2 6 10 10 10 2 2 6 22 22 22 170 170 170 231 231 231 250 250 250 253 253 253
--253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 246 246 246
--231 231 231 202 202 202 198 198 198 226 226 226 94 94 94 2 2 6 6 6 6 38 38 38
--30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 66 66 66
--26 26 26 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 6 8 8 33 49 54 29 43 47 6 8 12
--0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 74 74 74 50 50 50 2 2 6
--26 26 26 26 26 26 2 2 6 106 106 106 238 238 238 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 246 246 246 218 218 218 202 202 202 210 210 210 14 14 14 2 2 6 2 2 6
--30 30 30 22 22 22 2 2 6 2 2 6 2 2 6 2 2 6 18 18 18 86 86 86
--42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 17 20 33 49 54 17 23 26
--0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 90 90 90 22 22 22 2 2 6
--42 42 42 2 2 6 18 18 18 218 218 218 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 250 250 250 221 221 221 218 218 218 101 101 101 2 2 6 14 14 14
--18 18 18 38 38 38 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 78 78 78
--58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 22 25 36 54 60
--0 0 0 0 0 0 0 0 0 18 18 18 54 54 54 82 82 82 2 2 6 26 26 26
--22 22 22 2 2 6 124 127 131 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 250 250 250 238 238 238 198 198 198 6 6 6 38 38 38
--58 58 58 26 26 26 38 38 38 2 2 6 2 2 6 2 2 6 2 2 6 46 46 46
--78 78 78 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 30 33
--36 54 60 0 0 0 0 0 0 30 30 30 74 74 74 58 58 58 2 2 6 42 42 42
--2 2 6 22 22 22 231 231 231 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 246 246 246 46 46 46 38 38 38
--42 42 42 14 14 14 38 38 38 14 14 14 2 2 6 2 2 6 2 2 6 6 6 6
--86 86 86 46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--36 54 60 0 0 0 0 0 0 42 42 42 90 90 90 18 18 18 18 18 18 26 26 26
--2 2 6 116 116 116 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 250 250 250 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 94 94 94 6 6 6
--2 2 6 2 2 6 10 10 10 34 34 34 2 2 6 2 2 6 2 2 6 2 2 6
--74 74 74 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 36 54 60 26 26 26 66 66 66 82 82 82 2 2 6 38 38 38 6 6 6
--14 14 14 210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 246 246 246 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 151 151 151 2 2 6
--2 2 6 2 2 6 2 2 6 46 46 46 2 2 6 2 2 6 2 2 6 2 2 6
--42 42 42 74 74 74 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--6 6 6 36 54 60 21 30 33 90 90 90 26 26 26 6 6 6 42 42 42 2 2 6
--74 74 74 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 242 242 242 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 180 180 180 2 2 6
--2 2 6 2 2 6 2 2 6 46 46 46 2 2 6 2 2 6 2 2 6 2 2 6
--10 10 10 86 86 86 38 38 38 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--10 10 10 26 26 26 36 54 60 82 82 82 2 2 6 22 22 22 18 18 18 2 2 6
--151 151 151 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 202 202 202 2 2 6
--2 2 6 2 2 6 2 2 6 38 38 38 2 2 6 2 2 6 2 2 6 2 2 6
--6 6 6 86 86 86 46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--18 18 18 46 46 46 86 86 86 36 54 60 2 2 6 34 34 34 10 10 10 6 6 6
--210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 221 221 221 6 6 6
--2 2 6 2 2 6 6 6 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 82 82 82 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--26 26 26 66 66 66 62 62 62 2 2 6 2 2 6 38 38 38 10 10 10 26 26 26
--238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 231 231 231 6 6 6
--2 2 6 2 2 6 10 10 10 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 66 66 66 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--38 38 38 78 78 78 6 6 6 2 2 6 2 2 6 46 46 46 14 14 14 42 42 42
--246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 10 10 10
--2 2 6 2 2 6 22 22 22 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 66 66 66 62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18
--50 50 50 74 74 74 2 2 6 2 2 6 14 14 14 70 70 70 34 34 34 62 62 62
--250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 14 14 14
--2 2 6 2 2 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 66 66 66 62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18
--54 54 54 62 62 62 2 2 6 2 2 6 2 2 6 30 30 30 46 46 46 70 70 70
--250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 226 226 226 10 10 10
--2 2 6 6 6 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 66 66 66 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22
--58 58 58 62 62 62 2 2 6 2 2 6 2 2 6 2 2 6 30 30 30 78 78 78
--250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 202 202 202 2 2 6
--22 22 22 34 34 34 20 16 6 22 22 22 26 26 26 18 18 18 6 6 6 2 2 6
--2 2 6 82 82 82 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 26 26 26
--62 62 62 106 106 106 63 55 20 184 138 11 204 160 10 121 92 8 6 6 6 62 62 62
--238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 151 151 151 18 18 18
--14 14 14 2 2 6 2 2 6 2 2 6 6 6 6 18 18 18 66 66 66 38 38 38
--6 6 6 94 94 94 50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 6 6 6 10 10 10 10 10 10 18 18 18 38 38 38
--78 78 78 138 132 106 216 158 10 242 186 14 246 190 14 246 190 14 156 118 10 10 10 10
--90 90 90 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 246 230 190 214 187 87 214 187 87 185 146 40 35 31 12
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 46 46 46
--26 26 26 106 106 106 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 6 6 6 14 14 14 22 22 22 30 30 30 38 38 38 50 50 50 70 70 70
--106 106 106 185 146 40 226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 154 114 10
--6 6 6 74 74 74 226 226 226 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 237 201 50 241 196 14 241 208 19 232 195 16 35 31 12
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 30 30 30 26 26 26
--204 160 10 165 152 80 66 66 66 26 26 26 6 6 6 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--6 6 6 18 18 18 38 38 38 58 58 58 78 78 78 86 86 86 101 101 101 124 127 131
--174 140 55 210 150 10 234 174 13 246 186 14 246 190 14 246 190 14 246 190 14 237 188 10
--98 70 6 2 2 6 46 46 46 198 198 198 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 214 187 87 242 186 14 241 196 14 204 160 10 20 16 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 121 92 8
--238 202 15 232 195 16 82 82 82 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--14 14 14 38 38 38 70 70 70 148 132 55 185 146 40 200 144 11 197 138 11 197 138 11
--213 154 11 226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--220 174 15 35 31 12 2 2 6 22 22 22 151 151 151 250 250 250 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 250 250 250 242 242 242 214 187 87 239 182 13 237 188 10 213 154 11 35 31 12
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 42 6 220 174 15
--237 188 10 237 188 10 113 101 86 42 42 42 14 14 14 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--22 22 22 54 54 54 148 132 55 213 154 11 226 170 11 230 174 11 226 170 11 226 170 11
--236 178 12 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--241 196 14 184 138 11 10 10 10 2 2 6 6 6 6 116 116 116 242 242 242 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 231 231 231 198 198 198 213 164 39 236 178 12 236 178 12 210 150 10 137 92 6
--20 16 6 2 2 6 2 2 6 2 2 6 6 6 6 62 42 6 200 144 11 236 178 12
--239 182 13 239 182 13 124 112 88 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--30 30 30 70 70 70 169 125 40 226 170 11 239 182 13 242 186 14 242 186 14 246 186 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 232 195 16 98 70 6 2 2 6 2 2 6 2 2 6 66 66 66 221 221 221
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 202 202 202 198 198 198 213 164 39 230 174 11 230 174 11 216 158 10 192 133 9
--163 110 8 120 80 7 98 70 6 120 80 7 167 114 7 197 138 11 226 170 11 239 182 13
--242 186 14 242 186 14 165 152 80 78 78 78 34 34 34 14 14 14 6 6 6 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--30 30 30 78 78 78 185 146 40 226 170 11 239 182 13 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 241 196 14 204 160 10 20 16 6 2 2 6 2 2 6 2 2 6 38 38 38
--218 218 218 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--250 250 250 202 202 202 198 198 198 213 164 39 226 170 11 236 178 12 224 166 10 210 150 10
--200 144 11 197 138 11 192 133 9 197 138 11 210 150 10 226 170 11 242 186 14 246 190 14
--246 190 14 246 186 14 220 174 15 124 112 88 62 62 62 30 30 30 14 14 14 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--30 30 30 78 78 78 174 140 55 224 166 10 239 182 13 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 241 196 14 139 102 15 2 2 6 2 2 6 2 2 6 2 2 6
--78 78 78 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--250 250 250 214 214 214 198 198 198 185 146 40 219 162 10 236 178 12 234 174 13 224 166 10
--216 158 10 213 154 11 213 154 11 216 158 10 226 170 11 239 182 13 246 190 14 246 190 14
--246 190 14 246 190 14 242 186 14 213 164 39 101 101 101 58 58 58 30 30 30 14 14 14
--6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--30 30 30 74 74 74 174 140 55 216 158 10 236 178 12 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 241 196 14 230 187 11 62 42 6 2 2 6 2 2 6 2 2 6
--22 22 22 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 226 226 226 187 187 187 169 125 40 216 158 10 236 178 12 239 182 13 236 178 12
--230 174 11 226 170 11 226 170 11 230 174 11 236 178 12 242 186 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 186 14 239 182 13 213 164 39 106 106 106 66 66 66 34 34 34
--14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--26 26 26 70 70 70 149 139 69 213 154 11 236 178 12 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 241 196 14 190 146 13 20 16 6 2 2 6 2 2 6
--46 46 46 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 221 221 221 86 86 86 156 107 11 216 158 10 236 178 12 242 186 14 246 186 14
--242 186 14 239 182 13 239 182 13 242 186 14 242 186 14 246 186 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 220 174 15 149 139 69 66 66 66
--30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--26 26 26 70 70 70 149 139 69 210 150 10 236 178 12 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 121 92 8 34 34 34 106 106 106
--221 221 221 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--242 242 242 82 82 82 20 16 6 163 110 8 216 158 10 236 178 12 242 186 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 149 139 69
--46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10
--30 30 30 78 78 78 149 139 69 210 150 10 236 178 12 246 186 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 241 196 14 220 174 15 198 179 130 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 218 218 218
--58 58 58 2 2 6 20 16 6 167 114 7 216 158 10 236 178 12 246 186 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 242 186 14 185 146 40
--54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14
--38 38 38 86 86 86 169 125 40 213 154 11 236 178 12 246 186 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 190 146 13 214 214 214
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 170 170 170 26 26 26
--2 2 6 2 2 6 35 31 12 163 110 8 219 162 10 239 182 13 246 186 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 224 166 10 149 139 69
--46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18
--50 50 50 113 101 86 192 133 9 224 166 10 242 186 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 230 187 11 204 160 10 133 118 54
--226 226 226 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
--253 253 253 253 253 253 253 253 253 253 253 253 198 198 198 66 66 66 2 2 6 2 2 6
--2 2 6 2 2 6 62 42 6 156 107 11 219 162 10 239 182 13 246 186 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 242 186 14 234 174 13 213 154 11 148 132 55 66 66 66
--30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22
--58 58 58 148 132 55 206 145 10 234 174 13 242 186 14 246 186 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 204 160 10 163 110 8
--62 42 6 124 131 137 218 218 218 250 250 250 253 253 253 253 253 253 253 253 253 250 250 250
--242 242 242 210 210 210 151 151 151 66 66 66 6 6 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 62 42 6 163 110 8 216 158 10 236 178 12 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 239 182 13 230 174 11 216 158 10 185 146 40 124 112 88 70 70 70 38 38 38
--18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22
--62 62 62 169 125 40 206 145 10 224 166 10 236 178 12 239 182 13 242 186 14 242 186 14
--246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 236 178 12 216 158 10 171 120 8
--85 57 6 2 2 6 6 6 6 30 30 30 54 54 54 62 62 62 50 50 50 38 38 38
--14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 6 6 6 85 57 6 167 114 7 213 154 11 236 178 12 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 239 182 13 239 182 13
--230 174 11 210 150 10 174 140 55 124 112 88 82 82 82 54 54 54 34 34 34 18 18 18
--6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18
--50 50 50 169 125 40 192 133 9 200 144 11 216 158 10 219 162 10 224 166 10 226 170 11
--230 174 11 236 178 12 239 182 13 239 182 13 242 186 14 246 186 14 246 190 14 246 190 14
--246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 230 174 11 210 150 10 163 110 8
--104 69 6 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 6 6 6 85 57 6 167 114 7 206 145 10 230 174 11 242 186 14 246 190 14
--246 190 14 246 190 14 246 186 14 242 186 14 239 182 13 230 174 11 224 166 10 213 154 11
--169 125 40 124 112 88 86 86 86 58 58 58 38 38 38 22 22 22 10 10 10 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14
--34 34 34 70 70 70 133 118 54 169 125 40 167 114 7 180 123 7 192 133 9 197 138 11
--200 144 11 206 145 10 213 154 11 219 162 10 224 166 10 230 174 11 239 182 13 242 186 14
--246 186 14 246 186 14 246 186 14 246 186 14 239 182 13 216 158 10 184 138 11 152 99 6
--104 69 6 20 16 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6
--2 2 6 6 6 6 85 57 6 152 99 6 192 133 9 219 162 10 236 178 12 239 182 13
--246 186 14 242 186 14 239 182 13 236 178 12 224 166 10 206 145 10 192 133 9 148 132 55
--94 94 94 62 62 62 42 42 42 22 22 22 14 14 14 6 6 6 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--18 18 18 34 34 34 58 58 58 78 78 78 101 98 89 124 112 88 133 118 54 156 107 11
--163 110 8 167 114 7 171 120 8 180 123 7 184 138 11 197 138 11 210 150 10 219 162 10
--226 170 11 236 178 12 236 178 12 234 174 13 219 162 10 197 138 11 163 110 8 134 84 6
--85 57 6 10 10 10 2 2 6 2 2 6 18 18 18 38 38 38 38 38 38 38 38 38
--38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 26 26 26 2 2 6
--2 2 6 6 6 6 62 42 6 137 92 6 171 120 8 200 144 11 219 162 10 230 174 11
--234 174 13 230 174 11 219 162 10 210 150 10 192 133 9 163 110 8 124 112 88 82 82 82
--50 50 50 30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--6 6 6 14 14 14 22 22 22 34 34 34 42 42 42 58 58 58 74 74 74 86 86 86
--101 98 89 113 101 86 133 118 54 121 92 8 137 92 6 152 99 6 163 110 8 180 123 7
--184 138 11 197 138 11 206 145 10 200 144 11 180 123 7 156 107 11 134 84 6 104 69 6
--62 42 6 54 54 54 106 106 106 101 98 89 86 86 86 82 82 82 78 78 78 78 78 78
--78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 82 82 82 86 86 86 94 94 94
--106 106 106 101 101 101 90 61 47 120 80 7 156 107 11 180 123 7 192 133 9 200 144 11
--206 145 10 200 144 11 192 133 9 171 120 8 139 102 15 113 101 86 70 70 70 42 42 42
--22 22 22 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 6 6 6 10 10 10 14 14 14 22 22 22 30 30 30 38 38 38
--50 50 50 62 62 62 74 74 74 90 90 90 101 98 89 113 101 86 121 92 8 120 80 7
--137 92 6 152 99 6 152 99 6 152 99 6 134 84 6 120 80 7 98 70 6 88 55 22
--101 98 89 82 82 82 58 58 58 46 46 46 38 38 38 34 34 34 34 34 34 34 34 34
--34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 38 38 38 42 42 42
--54 54 54 82 82 82 94 86 71 85 57 6 134 84 6 156 107 11 167 114 7 171 120 8
--171 120 8 167 114 7 152 99 6 121 92 8 101 98 89 62 62 62 34 34 34 18 18 18
--6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 10 10 10
--18 18 18 22 22 22 30 30 30 42 42 42 50 50 50 66 66 66 86 86 86 101 98 89
--94 86 71 98 70 6 104 69 6 104 69 6 104 69 6 85 57 6 88 55 22 90 90 90
--62 62 62 38 38 38 22 22 22 14 14 14 10 10 10 10 10 10 10 10 10 10 10 10
--10 10 10 10 10 10 6 6 6 10 10 10 10 10 10 10 10 10 10 10 10 14 14 14
--22 22 22 42 42 42 70 70 70 94 86 71 85 57 6 104 69 6 120 80 7 137 92 6
--134 84 6 120 80 7 94 86 71 86 86 86 58 58 58 30 30 30 14 14 14 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 6 6 6 10 10 10 14 14 14 18 18 18 26 26 26 38 38 38 54 54 54
--70 70 70 86 86 86 94 86 71 94 86 71 94 86 71 86 86 86 74 74 74 50 50 50
--30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--6 6 6 18 18 18 34 34 34 58 58 58 82 82 82 94 86 71 94 86 71 94 86 71
--94 86 71 94 86 71 74 74 74 50 50 50 26 26 26 14 14 14 6 6 6 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 14 14 14 18 18 18
--30 30 30 38 38 38 46 46 46 54 54 54 50 50 50 42 42 42 30 30 30 18 18 18
--10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 6 6 6 14 14 14 26 26 26 38 38 38 50 50 50 58 58 58 58 58 58
--54 54 54 42 42 42 30 30 30 18 18 18 10 10 10 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6
--6 6 6 10 10 10 14 14 14 18 18 18 18 18 18 14 14 14 10 10 10 6 6 6
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 18 18 18 22 22 22 22 22 22
--18 18 18 14 14 14 10 10 10 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
--
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0
-+0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0
-+0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
-+10 15 3 2 3 1 12 18 4 42 61 14 19 27 6 11 16 4
-+38 55 13 10 15 3 3 4 1 10 15 3 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1
-+12 18 4 1 1 0 23 34 8 31 45 11 10 15 3 32 47 11
-+34 49 12 3 4 1 3 4 1 3 4 1 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 10 15 3 29 42 10 26 37 9 12 18 4
-+55 80 19 81 118 28 55 80 19 92 132 31 106 153 36 69 100 23
-+100 144 34 80 116 27 42 61 14 81 118 28 23 34 8 27 40 9
-+15 21 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 1 1 0 29 42 10 15 21 5 50 72 17
-+74 107 25 45 64 15 102 148 35 80 116 27 84 121 28 111 160 38
-+69 100 23 65 94 22 81 118 28 29 42 10 17 25 6 29 42 10
-+23 34 8 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1
-+15 21 5 15 21 5 34 49 12 101 146 34 111 161 38 97 141 33
-+97 141 33 119 172 41 117 170 40 116 167 40 118 170 40 118 171 40
-+117 169 40 118 170 40 111 160 38 118 170 40 96 138 32 89 128 30
-+81 118 28 11 16 4 10 15 3 1 1 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+3 4 1 3 4 1 34 49 12 101 146 34 79 115 27 111 160 38
-+114 165 39 113 163 39 118 170 40 117 169 40 118 171 40 117 169 40
-+116 167 40 119 172 41 113 163 39 92 132 31 105 151 36 113 163 39
-+75 109 26 19 27 6 16 23 5 11 16 4 0 1 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3
-+80 116 27 106 153 36 105 151 36 114 165 39 118 170 40 118 171 40
-+118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 170 40 117 169 40 118 170 40 118 170 40
-+117 170 40 75 109 26 75 109 26 34 49 12 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1
-+64 92 22 65 94 22 100 144 34 118 171 40 118 170 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 118 171 41 118 170 40 117 169 40
-+109 158 37 105 151 36 104 150 35 47 69 16 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+42 61 14 115 167 39 118 170 40 117 169 40 117 169 40 117 169 40
-+117 170 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 118 170 40 96 138 32 17 25 6 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 69 16
-+114 165 39 117 168 40 117 170 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 118 170 40 117 169 40 117 169 40 117 169 40
-+117 170 40 119 172 41 96 138 32 12 18 4 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3
-+32 47 11 105 151 36 118 170 40 117 169 40 117 169 40 116 168 40
-+109 157 37 111 160 38 117 169 40 118 171 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 118 171 40 69 100 23 2 3 1
-+0 0 0 0 0 0 0 0 0 0 0 0 19 27 6 101 146 34
-+118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 170 40
-+118 171 40 115 166 39 107 154 36 111 161 38 117 169 40 117 169 40
-+117 169 40 118 171 40 75 109 26 19 27 6 2 3 1 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 23 5
-+89 128 30 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+111 160 38 92 132 31 79 115 27 96 138 32 115 166 39 119 171 41
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 118 170 40 109 157 37 26 37 9
-+0 0 0 0 0 0 0 0 0 0 0 0 64 92 22 118 171 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 118 170 40 118 171 40 109 157 37
-+89 128 30 81 118 28 100 144 34 115 166 39 117 169 40 117 169 40
-+117 169 40 117 170 40 113 163 39 60 86 20 1 1 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+27 40 9 96 138 32 118 170 40 117 169 40 117 169 40 117 169 40
-+117 170 40 117 169 40 101 146 34 67 96 23 55 80 19 84 121 28
-+113 163 39 119 171 41 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 65 94 22
-+0 0 0 0 0 0 0 0 0 15 21 5 101 146 34 118 171 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 118 170 40 118 171 40 104 150 35 69 100 23 53 76 18
-+81 118 28 111 160 38 118 170 40 117 169 40 117 169 40 117 169 40
-+117 169 40 114 165 39 69 100 23 10 15 3 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
-+31 45 11 77 111 26 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 118 170 40 116 168 40 92 132 31 47 69 16
-+38 55 13 81 118 28 113 163 39 119 171 41 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 118 171 41 92 132 31
-+10 15 3 0 0 0 0 0 0 36 52 12 115 166 39 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40
-+118 171 40 102 148 35 64 92 22 34 49 12 65 94 22 106 153 36
-+118 171 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40
-+118 170 40 107 154 36 55 80 19 15 21 5 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+29 42 10 101 146 34 118 171 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 113 163 39
-+75 109 26 27 40 9 36 52 12 89 128 30 116 167 40 118 171 40
-+117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 104 150 35
-+16 23 5 0 0 0 0 0 0 53 76 18 118 171 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 109 157 37
-+67 96 23 23 34 8 42 61 14 96 138 32 118 170 40 118 170 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 74 107 25 10 15 3 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 31 45 11 101 146 34 118 170 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+119 171 41 102 148 35 47 69 16 14 20 5 50 72 17 102 148 35
-+118 171 40 117 169 40 117 169 40 117 169 40 118 170 40 102 148 35
-+15 21 5 0 0 0 0 0 0 50 72 17 118 170 40 117 169 40
-+117 169 40 117 169 40 118 170 40 116 167 40 84 121 28 27 40 9
-+19 27 6 74 107 25 114 165 39 118 171 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 75 109 26 10 15 4 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 38 55 13 102 148 35 118 171 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 118 170 40 115 167 39 77 111 26 17 25 6 19 27 6
-+77 111 26 115 166 39 118 170 40 117 169 40 119 172 41 81 118 28
-+3 4 1 0 0 0 0 0 0 27 40 9 111 160 38 118 170 40
-+117 169 40 118 171 40 105 151 36 50 72 17 10 15 3 38 55 13
-+100 144 34 118 171 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 79 115 27 15 21 5 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 10 15 3 64 92 22 111 160 38 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 118 171 40 96 138 32 32 47 11
-+3 4 1 50 72 17 107 154 36 120 173 41 105 151 36 31 45 11
-+0 0 0 0 0 0 0 0 0 3 4 1 65 94 22 117 169 40
-+118 170 40 89 128 30 26 37 9 3 4 1 60 86 20 111 161 38
-+118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+97 141 33 36 52 12 1 1 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 14 20 5 75 109 26 117 168 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 107 154 36
-+45 64 15 2 3 1 31 45 11 75 109 26 32 47 11 0 1 0
-+0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 55 80 19
-+65 94 22 11 16 4 11 16 4 75 109 26 116 168 40 118 170 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 107 154 36
-+47 69 16 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 12 18 4 69 100 23 111 161 38 118 171 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40
-+111 160 38 50 72 17 2 3 1 2 3 1 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
-+1 1 0 12 18 4 81 118 28 118 170 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 170 40 118 171 40 101 146 34
-+42 61 14 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 3 4 1 36 52 12 89 128 30
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+118 171 41 101 146 34 14 20 5 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 47 69 16 118 170 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 170 40 111 160 38 69 100 23 19 27 6
-+0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 11 16 4 69 100 23
-+115 167 39 119 172 41 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+119 172 41 75 109 26 3 4 1 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 23 34 8 106 153 36 118 170 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+117 169 40 118 170 40 119 172 41 105 151 36 42 61 14 2 3 1
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 15 21 5
-+45 64 15 80 116 27 114 165 39 118 170 40 117 169 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 119 172 41
-+97 141 33 20 30 7 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 1 1 0 53 76 18 114 165 39 118 171 40 117 169 40
-+117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40
-+118 171 40 104 150 35 64 92 22 31 45 11 10 15 3 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 36 52 12 97 141 33 109 158 37 113 163 39 116 168 40
-+117 169 40 117 170 40 118 170 40 119 172 41 115 167 39 84 121 28
-+23 34 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 3 4 1 50 72 17 102 148 35 118 171 40
-+119 171 41 118 170 40 117 169 40 117 169 40 115 166 39 111 161 38
-+109 157 37 79 115 27 12 18 4 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 3 4 1 15 21 5 23 34 8 45 64 15 106 153 36
-+116 167 40 111 160 38 101 146 34 79 115 27 42 61 14 10 15 3
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 1 1 0 20 30 7 60 86 20
-+89 128 30 106 153 36 113 163 39 117 169 40 84 121 28 29 42 10
-+19 27 6 10 15 3 2 3 1 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 38 55 13
-+36 52 12 26 37 9 12 18 4 2 3 1 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 1 0 0 19 2 7 52 5 18
-+78 7 27 88 8 31 81 7 29 56 5 19 25 2 9 3 0 1
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+3 4 1 19 27 6 31 45 11 38 55 13 32 47 11 3 4 1
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1
-+9 0 3 12 1 4 9 0 3 4 0 1 0 0 0 0 0 0
-+0 0 0 0 0 0 28 3 10 99 9 35 156 14 55 182 16 64
-+189 17 66 190 17 67 189 17 66 184 17 65 166 15 58 118 13 41
-+45 4 16 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 11 1 4 52 5 18 101 9 35 134 12 47
-+151 14 53 154 14 54 151 14 53 113 10 40 11 1 4 0 0 0
-+3 0 1 67 6 24 159 14 56 190 17 67 190 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 191 17 67
-+174 16 61 101 9 35 14 1 5 0 0 0 35 3 12 108 10 38
-+122 11 43 122 11 43 112 10 39 87 8 30 50 5 17 13 1 5
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+3 0 1 56 5 19 141 13 49 182 16 64 191 17 67 191 17 67
-+190 17 67 190 17 67 191 17 67 113 10 40 3 0 1 1 0 0
-+79 7 28 180 16 63 190 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+189 17 66 188 17 66 122 11 43 11 1 4 41 4 14 176 16 62
-+191 17 67 191 17 67 191 17 67 190 17 67 181 16 63 146 13 51
-+75 7 26 10 1 4 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 2
-+90 8 32 178 16 62 191 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 41 4 14
-+173 16 61 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 88 8 31 1 0 0 89 8 31
-+185 17 65 189 17 66 188 17 66 188 17 66 189 17 66 191 17 67
-+186 17 65 124 11 43 25 2 9 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 89 8 31
-+184 17 65 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+190 17 67 151 14 53 34 3 12 0 0 0 0 0 0 79 7 28
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 191 17 67 146 13 51 9 1 3 7 1 2
-+108 10 38 187 17 66 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 176 16 62
-+189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67
-+151 14 53 38 3 13 0 0 0 0 0 0 0 0 0 50 5 17
-+180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 191 17 67 141 13 49 7 1 3 0 0 0
-+11 1 4 112 10 39 187 17 66 189 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 190 17 67 113 10 40 5 0 2 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 7 1 3 132 12 46 191 17 67
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 146 13 51
-+35 3 12 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2
-+101 9 35 185 17 65 190 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 190 17 67 180 16 63 67 6 24 0 0 0 0 0 0
-+0 0 0 11 1 4 108 10 38 186 17 65 189 17 66 188 17 66
-+188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 44 4 15 177 16 62 189 17 66
-+188 17 66 188 17 66 189 17 66 189 17 66 134 12 47 28 3 10
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+8 1 3 79 7 28 159 14 56 188 17 66 191 17 67 190 17 67
-+189 17 66 189 17 66 189 17 66 189 17 66 190 17 67 191 17 67
-+188 17 66 158 14 55 72 7 25 4 0 1 0 0 0 0 0 0
-+0 0 0 0 0 0 8 1 3 95 9 33 182 16 64 189 17 67
-+188 17 66 188 17 66 188 17 66 191 17 67 122 11 43 3 0 1
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 88 8 31 190 17 67 188 17 66
-+188 17 66 189 17 66 185 17 65 113 10 40 18 2 6 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 1 0 0 24 2 8 77 7 27 124 11 43 154 14 54
-+168 15 59 173 16 61 173 16 61 168 15 59 154 14 54 124 11 43
-+77 7 27 22 2 8 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 5 0 2 77 7 27 173 16 61
-+190 17 67 188 17 66 188 17 66 190 17 67 164 15 57 23 2 8
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 1 0 0 118 13 41 191 17 67 188 17 66
-+190 17 67 174 16 61 87 8 30 8 1 3 0 0 0 0 0 0
-+0 0 0 0 0 0 10 1 4 29 3 10 40 4 14 36 3 13
-+18 2 6 2 0 1 0 0 0 0 0 0 3 0 1 14 1 5
-+26 2 9 33 3 11 32 3 11 25 2 9 13 1 5 3 0 1
-+0 0 0 14 1 5 56 5 19 95 9 33 109 10 38 101 9 35
-+77 7 27 35 3 12 5 0 2 0 0 0 1 0 0 56 5 19
-+156 14 55 190 17 67 188 17 66 188 17 66 182 16 64 50 5 17
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 189 17 66
-+151 14 53 52 5 18 2 0 1 0 0 0 0 0 0 1 0 0
-+28 3 10 90 8 32 146 13 51 170 15 60 178 16 62 174 16 61
-+158 14 55 112 10 39 40 4 14 1 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1
-+56 5 19 146 13 51 183 17 64 191 17 67 191 17 67 191 17 67
-+188 17 66 173 16 61 122 11 43 41 4 14 1 0 0 0 0 0
-+30 3 10 124 11 43 185 17 65 190 17 67 187 17 66 67 6 24
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 6 1 2 134 12 47 168 15 59 99 9 35
-+21 2 7 0 0 0 0 0 0 0 0 0 6 1 2 77 7 27
-+162 15 57 190 17 67 191 17 67 189 17 66 189 17 66 189 17 66
-+190 17 67 191 17 67 169 15 59 75 7 26 3 0 1 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 79 7 28
-+178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 191 17 67 170 15 60 79 7 28 5 0 2
-+0 0 0 10 1 3 78 7 27 159 14 56 188 17 66 75 7 26
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 1 0 0 35 3 12 29 3 10 2 0 1
-+0 0 0 0 0 0 0 0 0 9 1 3 101 9 35 183 17 64
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 190 17 67 178 16 63 67 6 23 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 174 16 61
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 190 17 67 182 16 64 89 8 31
-+4 0 1 0 0 0 0 0 0 25 2 9 73 7 26 31 3 11
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 4 0 1 98 9 34 187 17 66 189 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 25 2 9
-+0 0 0 0 0 0 0 0 0 8 1 3 134 12 47 191 17 67
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 180 16 63
-+68 6 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 6 1 2 19 2 7 3 0 1 0 0 0 0 0 0
-+0 0 0 0 0 0 65 6 23 180 16 63 189 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 83 8 29
-+0 0 0 0 0 0 0 0 0 41 4 14 177 16 62 189 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67
-+159 14 56 28 3 10 0 0 0 0 0 0 0 0 0 23 2 8
-+41 4 14 5 0 2 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+23 2 8 113 10 40 159 14 56 65 6 23 0 0 0 0 0 0
-+0 0 0 16 1 6 146 13 51 191 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 132 12 46
-+5 0 2 0 0 0 0 0 0 77 7 27 189 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+190 17 67 98 9 34 0 0 0 0 0 0 12 1 4 134 12 47
-+178 16 63 108 10 38 16 1 6 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 3 10
-+141 13 49 190 17 67 191 17 67 134 12 47 6 1 2 0 0 0
-+0 0 0 68 6 24 186 17 65 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 156 14 55
-+14 1 5 0 0 0 0 0 0 98 9 34 191 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+190 17 67 156 14 55 19 2 7 0 0 0 47 4 16 181 16 63
-+190 17 67 189 17 66 126 14 44 17 2 6 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 16 1 6 134 12 47
-+191 17 67 188 17 66 190 17 67 162 15 57 19 2 7 0 0 0
-+3 0 1 123 11 43 191 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 163 15 57
-+20 2 7 0 0 0 0 0 0 101 9 35 191 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 182 16 64 52 5 18 0 0 0 73 7 26 188 17 66
-+188 17 66 188 17 66 189 17 66 109 10 38 5 0 2 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 95 9 33 189 17 66
-+188 17 66 188 17 66 189 17 66 171 15 60 29 3 10 0 0 0
-+16 1 6 156 14 55 190 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 158 14 55
-+17 2 6 0 0 0 0 0 0 85 8 30 190 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 81 7 29 0 0 0 85 8 30 190 17 67
-+188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 25 2 9 162 15 57 190 17 67
-+188 17 66 188 17 66 189 17 66 173 16 61 31 3 11 0 0 0
-+30 3 10 171 15 60 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 141 13 49
-+7 1 2 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 191 17 67 98 9 34 0 0 0 88 8 31 190 17 67
-+188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 5 0 2
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 68 6 24 187 17 66 188 17 66
-+188 17 66 188 17 66 189 17 66 170 15 60 28 3 10 0 0 0
-+34 3 12 174 16 61 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 101 9 35
-+0 0 0 0 0 0 0 0 0 21 2 7 159 14 56 190 17 67
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 191 17 67 98 9 34 0 0 0 81 7 29 189 17 66
-+188 17 66 188 17 66 188 17 66 189 17 66 168 15 59 28 3 10
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 109 10 38 191 17 67 188 17 66
-+188 17 66 188 17 66 190 17 67 163 15 57 21 2 7 0 0 0
-+26 2 9 168 15 59 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 47 4 16
-+0 0 0 0 0 0 0 0 0 0 0 0 108 10 38 190 17 67
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 78 7 27 0 0 0 68 6 24 187 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 183 17 64 56 5 19
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 3 0 1 131 12 46 191 17 67 188 17 66
-+188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 0 0 0
-+11 1 4 146 13 51 190 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 191 17 67 126 14 44 7 1 2
-+0 0 0 0 0 0 0 0 0 0 0 0 32 3 11 164 15 58
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+189 17 66 178 16 62 44 4 15 0 0 0 50 5 17 182 16 64
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 188 17 66
-+188 17 66 188 17 66 191 17 67 131 12 46 3 0 1 0 0 0
-+0 0 0 101 9 35 190 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 190 17 67 170 15 60 44 4 15 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 7 27
-+183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+191 17 67 134 12 47 9 1 3 0 0 0 31 3 11 171 15 60
-+189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 2 0 1 124 11 43 191 17 67 188 17 66
-+188 17 66 188 17 66 191 17 67 101 9 35 0 0 0 0 0 0
-+0 0 0 35 3 12 168 15 59 190 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 182 16 64 77 7 27 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 1 2
-+99 9 35 185 17 65 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66
-+177 16 62 56 5 19 0 0 0 0 0 0 13 1 5 151 14 53
-+190 17 67 188 17 66 188 17 66 188 17 66 185 17 65 56 5 19
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 99 9 35 191 17 67 188 17 66
-+188 17 66 188 17 66 186 17 65 65 6 23 0 0 0 0 0 0
-+0 0 0 0 0 0 79 7 28 182 16 64 190 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+191 17 67 177 16 62 83 8 29 4 0 1 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+8 1 3 89 8 31 175 16 62 191 17 67 189 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 181 16 63
-+85 8 30 3 0 1 0 0 0 0 0 0 1 0 0 118 13 41
-+191 17 67 188 17 66 188 17 66 189 17 66 173 16 61 34 3 12
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66
-+188 17 66 189 17 66 169 15 59 30 3 10 0 0 0 0 0 0
-+0 0 0 0 0 0 5 0 2 83 8 29 173 16 61 191 17 67
-+190 17 67 189 17 66 189 17 66 190 17 67 191 17 67 187 17 66
-+151 14 53 56 5 19 3 0 1 0 0 0 16 1 6 50 5 17
-+79 7 28 95 9 33 95 9 33 75 7 26 41 4 14 10 1 4
-+0 0 0 2 0 1 50 5 17 132 12 46 178 16 62 190 17 67
-+191 17 67 191 17 67 191 17 67 186 17 65 154 14 54 68 6 24
-+4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25
-+187 17 66 188 17 66 188 17 66 191 17 67 141 13 49 9 1 3
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 14 1 5 151 14 53 190 17 67
-+188 17 66 191 17 67 131 12 46 5 0 2 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 2 0 1 44 4 15 113 10 40
-+156 14 55 173 16 61 174 16 61 164 15 58 134 12 47 77 7 27
-+18 2 6 0 0 0 16 1 6 85 8 30 151 14 53 182 16 64
-+189 17 66 191 17 67 190 17 67 188 17 66 177 16 62 141 13 49
-+68 6 24 8 1 3 0 0 0 8 1 3 44 4 15 88 8 31
-+113 10 40 122 11 43 108 10 38 67 6 24 20 2 7 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 3 10
-+166 15 58 190 17 67 188 17 66 187 17 66 79 7 28 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 73 7 26 185 17 65
-+189 17 66 184 17 65 65 6 23 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1
-+17 2 6 32 3 11 34 3 12 22 2 8 6 1 2 0 0 0
-+0 0 0 38 3 13 141 13 49 188 17 66 190 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 191 17 67
-+184 17 65 122 11 43 21 2 7 0 0 0 0 0 0 0 0 0
-+0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
-+108 10 38 191 17 67 191 17 67 141 13 49 16 1 6 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 8 1 3 112 10 39
-+186 17 65 124 11 43 10 1 4 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+36 3 13 156 14 55 191 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+189 17 66 190 17 67 134 12 47 18 2 6 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 7 1 2 41 4 14 75 7 26 66 5 23 19 2 7
-+26 2 9 144 13 50 154 14 54 40 4 14 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5
-+56 5 19 19 2 7 0 0 0 7 1 2 29 3 10 35 3 12
-+19 2 7 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5
-+134 12 47 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 189 17 67 108 10 38 3 0 1 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
-+40 4 14 124 11 43 177 16 62 188 17 66 187 17 66 144 13 50
-+24 2 8 17 2 6 22 2 8 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 19 2 7 122 11 43 171 15 60 175 16 62
-+159 14 56 112 10 39 40 4 14 2 0 1 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25
-+186 17 65 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 189 17 66 174 16 61 41 4 14 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 72 7 25
-+168 15 59 191 17 67 189 17 66 188 17 66 188 17 66 190 17 67
-+95 9 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 95 9 33 191 17 67 189 17 66 189 17 66
-+190 17 67 191 17 67 171 15 60 90 8 32 12 1 4 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 132 12 46
-+191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 190 17 67 98 9 34 0 0 0
-+0 0 0 0 0 0 0 0 0 5 0 2 88 8 31 180 16 63
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 191 17 67
-+146 13 51 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 9 1 3 144 13 50 191 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 189 17 66 187 17 66 123 11 43 20 2 7
-+0 0 0 0 0 0 0 0 0 0 0 0 21 2 7 163 15 57
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 191 17 67 134 12 47 5 0 2
-+0 0 0 0 0 0 3 0 1 88 8 31 182 16 64 189 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66
-+171 15 60 31 3 11 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 20 2 7 162 15 57 190 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 132 12 46
-+20 2 7 0 0 0 0 0 0 0 0 0 32 3 11 173 16 61
-+189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 190 17 67 151 14 53 12 1 4
-+0 0 0 0 0 0 72 7 25 180 16 63 189 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+181 16 63 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 21 2 7 163 15 57 190 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67
-+122 11 43 9 1 3 0 0 0 0 0 0 30 3 10 171 15 60
-+189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 10 1 4
-+0 0 0 38 3 13 166 15 58 190 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+183 17 64 52 5 18 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 13 1 5 154 14 54 190 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+186 17 65 79 7 28 0 0 0 0 0 0 14 1 5 156 14 54
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 2 0 1
-+5 0 2 122 11 43 191 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+182 16 64 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 3 0 1 126 14 44 191 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+190 17 67 158 14 55 23 2 8 0 0 0 1 0 0 113 10 40
-+191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 78 7 27 0 0 0
-+47 4 16 177 16 62 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66
-+173 16 61 34 3 12 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 85 8 30 189 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 79 7 28 0 0 0 0 0 0 47 4 16
-+175 16 62 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 190 17 67 156 14 55 22 2 8 0 0 0
-+109 10 38 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67
-+151 14 53 13 1 5 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 35 3 12 173 16 61 189 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 191 17 67 134 12 47 7 1 2 0 0 0 3 0 1
-+99 9 35 188 17 66 189 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 181 16 63 68 6 24 0 0 0 18 2 6
-+156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67
-+101 9 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 3 0 1 118 13 41 191 17 67 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 168 15 59 28 3 10 0 0 0 0 0 0
-+12 1 4 113 10 40 187 17 66 189 17 67 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+190 17 67 180 16 63 88 8 31 4 0 1 0 0 0 47 4 16
-+180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 168 15 59
-+36 3 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 38 3 13 164 15 58 190 17 67
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0
-+0 0 0 11 1 4 90 8 32 169 15 59 190 17 67 190 17 67
-+189 17 66 189 17 66 189 17 66 189 17 66 191 17 67 189 17 66
-+158 14 55 68 6 24 4 0 1 0 0 0 0 0 0 73 7 26
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 189 17 66 185 17 65 83 8 29
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 65 6 23 174 16 61
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 185 17 65 56 5 19 0 0 0 0 0 0
-+0 0 0 0 0 0 2 0 1 35 3 12 99 9 35 146 13 51
-+170 15 60 177 16 62 177 16 62 166 15 58 141 13 49 85 8 30
-+24 2 8 0 0 0 0 0 0 0 0 0 0 0 0 85 8 30
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 189 17 66 112 10 39 8 1 3
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 68 6 24
-+170 15 60 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 11 1 4
-+28 3 10 40 4 14 38 3 13 25 2 9 8 1 3 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 7 27
-+189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 187 17 66 113 10 40 14 1 5 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
-+47 4 16 141 13 49 186 17 65 191 17 67 190 17 67 189 17 66
-+189 17 66 191 17 67 156 14 55 20 2 7 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 4 15
-+178 16 62 190 17 67 188 17 66 188 17 66 188 17 66 190 17 67
-+191 17 67 173 16 61 90 8 32 10 1 4 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 14 1 5 68 6 24 131 12 46 162 15 57 174 16 61
-+171 15 60 146 13 51 56 5 19 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 3 0 1 14 1 5 29 3 10
-+41 4 14 47 4 16 50 5 17 45 4 16 34 3 12 18 2 6
-+5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2
-+90 8 32 169 15 59 185 17 65 187 17 66 182 16 64 163 15 57
-+113 10 40 41 4 14 2 0 1 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 5 0 2 21 2 7 34 3 12
-+29 3 10 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0
-+3 0 1 32 3 11 79 7 28 124 11 43 154 14 54 171 15 60
-+180 16 63 182 16 64 182 16 64 180 16 63 174 16 61 159 14 56
-+132 12 46 88 8 31 34 3 12 3 0 1 0 0 0 0 0 0
-+3 0 1 29 3 10 56 5 19 65 6 23 50 5 17 23 2 8
-+3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 2 9
-+109 10 38 169 15 59 189 17 66 191 17 67 190 17 67 189 17 66
-+189 17 66 188 17 66 188 17 66 188 17 66 189 17 66 190 17 67
-+191 17 67 190 17 67 171 15 60 98 9 34 10 1 3 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 14 1 5 141 13 49
-+191 17 67 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 189 17 67 186 17 65 65 6 23 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 23 2 8 166 15 58
-+190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 189 17 66 176 16 62 45 4 16 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 83 8 29
-+183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+188 17 66 189 17 66 185 17 65 95 9 33 3 0 1 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2
-+85 8 30 176 16 62 191 17 67 188 17 66 188 17 66 188 17 66
-+188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66
-+191 17 67 180 16 63 95 9 33 7 1 3 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+2 0 1 52 5 18 141 13 49 185 17 65 191 17 67 189 17 67
-+189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 187 17 66
-+146 13 51 56 5 19 4 0 1 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 14 1 5 68 6 24 131 12 46 166 15 58
-+180 16 63 183 17 64 180 16 63 168 15 59 134 12 47 75 7 26
-+17 2 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 24 2 8
-+44 4 15 52 5 18 45 4 16 26 2 9 6 1 2 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+0 0 0 0 0 0 0 0 0
-diff -Nur linux-3.11.10.orig/drivers/video/Makefile linux-3.11.10/drivers/video/Makefile
---- linux-3.11.10.orig/drivers/video/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/video/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -100,6 +100,7 @@
- obj-$(CONFIG_FB_VOODOO1) += sstfb.o
- obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
- obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o
-+obj-$(CONFIG_FB_BCM2708) += bcm2708_fb.o
- obj-$(CONFIG_FB_68328) += 68328fb.o
- obj-$(CONFIG_FB_GBE) += gbefb.o
- obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
-diff -Nur linux-3.11.10.orig/drivers/w1/masters/w1-gpio.c linux-3.11.10/drivers/w1/masters/w1-gpio.c
---- linux-3.11.10.orig/drivers/w1/masters/w1-gpio.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/w1/masters/w1-gpio.c 2014-02-07 19:57:30.000000000 +0100
-@@ -22,6 +22,9 @@
- #include "../w1.h"
- #include "../w1_int.h"
-
-+static int w1_gpio_pullup = 0;
-+module_param_named(pullup, w1_gpio_pullup, int, 0);
-+
- static void w1_gpio_write_bit_dir(void *data, u8 bit)
- {
- struct w1_gpio_platform_data *pdata = data;
-@@ -46,6 +49,16 @@
- return gpio_get_value(pdata->pin) ? 1 : 0;
- }
-
-+static void w1_gpio_bitbang_pullup(void *data, u8 on)
-+{
-+ struct w1_gpio_platform_data *pdata = data;
-+
-+ if (on)
-+ gpio_direction_output(pdata->pin, 1);
-+ else
-+ gpio_direction_input(pdata->pin);
-+}
-+
- #if defined(CONFIG_OF)
- static struct of_device_id w1_gpio_dt_ids[] = {
- { .compatible = "w1-gpio" },
-@@ -127,6 +140,13 @@
- master->write_bit = w1_gpio_write_bit_dir;
- }
-
-+ if (w1_gpio_pullup)
-+ if (pdata->is_open_drain)
-+ printk(KERN_ERR "w1-gpio 'pullup' option "
-+ "doesn't work with open drain GPIO\n");
-+ else
-+ master->bitbang_pullup = w1_gpio_bitbang_pullup;
-+
- err = w1_add_master_device(master);
- if (err) {
- dev_err(&pdev->dev, "w1_add_master device failed\n");
-diff -Nur linux-3.11.10.orig/drivers/w1/w1.h linux-3.11.10/drivers/w1/w1.h
---- linux-3.11.10.orig/drivers/w1/w1.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/w1/w1.h 2014-02-07 19:57:30.000000000 +0100
-@@ -148,6 +148,12 @@
- */
- u8 (*set_pullup)(void *, int);
-
-+ /**
-+ * Turns the pullup on/off in bitbanging mode, takes an on/off argument.
-+ * @return -1=Error, 0=completed
-+ */
-+ void (*bitbang_pullup) (void *, u8);
-+
- /** Really nice hardware can handles the different types of ROM search
- * w1_master* is passed to the slave found callback.
- */
-diff -Nur linux-3.11.10.orig/drivers/w1/w1_int.c linux-3.11.10/drivers/w1/w1_int.c
---- linux-3.11.10.orig/drivers/w1/w1_int.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/w1/w1_int.c 2014-02-07 19:57:30.000000000 +0100
-@@ -117,19 +117,21 @@
- printk(KERN_ERR "w1_add_master_device: invalid function set\n");
- return(-EINVAL);
- }
-- /* While it would be electrically possible to make a device that
-- * generated a strong pullup in bit bang mode, only hardware that
-- * controls 1-wire time frames are even expected to support a strong
-- * pullup. w1_io.c would need to support calling set_pullup before
-- * the last write_bit operation of a w1_write_8 which it currently
-- * doesn't.
-- */
-+
-+ /* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup
-+ * and takes care of timing itself */
- if (!master->write_byte && !master->touch_bit && master->set_pullup) {
- printk(KERN_ERR "w1_add_master_device: set_pullup requires "
- "write_byte or touch_bit, disabling\n");
- master->set_pullup = NULL;
- }
-
-+ if (master->set_pullup && master->bitbang_pullup) {
-+ printk(KERN_ERR "w1_add_master_device: set_pullup should not "
-+ "be set when bitbang_pullup is used, disabling\n");
-+ master->set_pullup = NULL;
-+ }
-+
- /* Lock until the device is added (or not) to w1_masters. */
- mutex_lock(&w1_mlock);
- /* Search for the first available id (starting at 1). */
-diff -Nur linux-3.11.10.orig/drivers/w1/w1_io.c linux-3.11.10/drivers/w1/w1_io.c
---- linux-3.11.10.orig/drivers/w1/w1_io.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/w1/w1_io.c 2014-02-07 19:57:30.000000000 +0100
-@@ -127,10 +127,22 @@
- static void w1_post_write(struct w1_master *dev)
- {
- if (dev->pullup_duration) {
-- if (dev->enable_pullup && dev->bus_master->set_pullup)
-- dev->bus_master->set_pullup(dev->bus_master->data, 0);
-- else
-+ if (dev->enable_pullup) {
-+ if (dev->bus_master->set_pullup) {
-+ dev->bus_master->set_pullup(dev->
-+ bus_master->data,
-+ 0);
-+ } else if (dev->bus_master->bitbang_pullup) {
-+ dev->bus_master->
-+ bitbang_pullup(dev->bus_master->data, 1);
- msleep(dev->pullup_duration);
-+ dev->bus_master->
-+ bitbang_pullup(dev->bus_master->data, 0);
-+ }
-+ } else {
-+ msleep(dev->pullup_duration);
-+ }
-+
- dev->pullup_duration = 0;
- }
- }
-diff -Nur linux-3.11.10.orig/drivers/watchdog/bcm2708_wdog.c linux-3.11.10/drivers/watchdog/bcm2708_wdog.c
---- linux-3.11.10.orig/drivers/watchdog/bcm2708_wdog.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/drivers/watchdog/bcm2708_wdog.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,384 @@
-+/*
-+ * Broadcom BCM2708 watchdog driver.
-+ *
-+ * (c) Copyright 2010 Broadcom Europe Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version
-+ * 2 of the License, or (at your option) any later version.
-+ *
-+ * BCM2708 watchdog driver. Loosely based on wdt driver.
-+ */
-+
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/types.h>
-+#include <linux/miscdevice.h>
-+#include <linux/watchdog.h>
-+#include <linux/fs.h>
-+#include <linux/ioport.h>
-+#include <linux/notifier.h>
-+#include <linux/reboot.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/uaccess.h>
-+#include <mach/platform.h>
-+
-+#include <asm/system.h>
-+
-+#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
-+#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
-+
-+static unsigned long wdog_is_open;
-+static uint32_t wdog_ticks; /* Ticks to load into wdog timer */
-+static char expect_close;
-+
-+/*
-+ * Module parameters
-+ */
-+
-+#define WD_TIMO 10 /* Default heartbeat = 60 seconds */
-+static int heartbeat = WD_TIMO; /* Heartbeat in seconds */
-+
-+module_param(heartbeat, int, 0);
-+MODULE_PARM_DESC(heartbeat,
-+ "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
-+ __MODULE_STRING(WD_TIMO) ")");
-+
-+static int nowayout = WATCHDOG_NOWAYOUT;
-+module_param(nowayout, int, 0);
-+MODULE_PARM_DESC(nowayout,
-+ "Watchdog cannot be stopped once started (default="
-+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-+
-+static DEFINE_SPINLOCK(wdog_lock);
-+
-+/**
-+ * Start the watchdog driver.
-+ */
-+
-+static int wdog_start(unsigned long timeout)
-+{
-+ uint32_t cur;
-+ unsigned long flags;
-+ spin_lock_irqsave(&wdog_lock, flags);
-+
-+ /* enable the watchdog */
-+ iowrite32(PM_PASSWORD | (timeout & PM_WDOG_TIME_SET),
-+ __io_address(PM_WDOG));
-+ cur = ioread32(__io_address(PM_RSTC));
-+ iowrite32(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) |
-+ PM_RSTC_WRCFG_FULL_RESET, __io_address(PM_RSTC));
-+
-+ spin_unlock_irqrestore(&wdog_lock, flags);
-+ return 0;
-+}
-+
-+/**
-+ * Stop the watchdog driver.
-+ */
-+
-+static int wdog_stop(void)
-+{
-+ iowrite32(PM_PASSWORD | PM_RSTC_RESET, __io_address(PM_RSTC));
-+ printk(KERN_INFO "watchdog stopped\n");
-+ return 0;
-+}
-+
-+/**
-+ * Reload counter one with the watchdog heartbeat. We don't bother
-+ * reloading the cascade counter.
-+ */
-+
-+static void wdog_ping(void)
-+{
-+ wdog_start(wdog_ticks);
-+}
-+
-+/**
-+ * @t: the new heartbeat value that needs to be set.
-+ *
-+ * Set a new heartbeat value for the watchdog device. If the heartbeat
-+ * value is incorrect we keep the old value and return -EINVAL. If
-+ * successful we return 0.
-+ */
-+
-+static int wdog_set_heartbeat(int t)
-+{
-+ if (t < 1 || t > WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET))
-+ return -EINVAL;
-+
-+ heartbeat = t;
-+ wdog_ticks = SECS_TO_WDOG_TICKS(t);
-+ return 0;
-+}
-+
-+/**
-+ * @file: file handle to the watchdog
-+ * @buf: buffer to write (unused as data does not matter here
-+ * @count: count of bytes
-+ * @ppos: pointer to the position to write. No seeks allowed
-+ *
-+ * A write to a watchdog device is defined as a keepalive signal.
-+ *
-+ * if 'nowayout' is set then normally a close() is ignored. But
-+ * if you write 'V' first then the close() will stop the timer.
-+ */
-+
-+static ssize_t wdog_write(struct file *file, const char __user *buf,
-+ size_t count, loff_t *ppos)
-+{
-+ if (count) {
-+ if (!nowayout) {
-+ size_t i;
-+
-+ /* In case it was set long ago */
-+ expect_close = 0;
-+
-+ for (i = 0; i != count; i++) {
-+ char c;
-+ if (get_user(c, buf + i))
-+ return -EFAULT;
-+ if (c == 'V')
-+ expect_close = 42;
-+ }
-+ }
-+ wdog_ping();
-+ }
-+ return count;
-+}
-+
-+static int wdog_get_status(void)
-+{
-+ unsigned long flags;
-+ int status = 0;
-+ spin_lock_irqsave(&wdog_lock, flags);
-+ /* FIXME: readback reset reason */
-+ spin_unlock_irqrestore(&wdog_lock, flags);
-+ return status;
-+}
-+
-+static uint32_t wdog_get_remaining(void)
-+{
-+ uint32_t ret = ioread32(__io_address(PM_WDOG));
-+ return ret & PM_WDOG_TIME_SET;
-+}
-+
-+/**
-+ * @file: file handle to the device
-+ * @cmd: watchdog command
-+ * @arg: argument pointer
-+ *
-+ * The watchdog API defines a common set of functions for all watchdogs
-+ * according to their available features. We only actually usefully support
-+ * querying capabilities and current status.
-+ */
-+
-+static long wdog_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ void __user *argp = (void __user *)arg;
-+ int __user *p = argp;
-+ int new_heartbeat;
-+ int status;
-+ int options;
-+ uint32_t remaining;
-+
-+ struct watchdog_info ident = {
-+ .options = WDIOF_SETTIMEOUT|
-+ WDIOF_MAGICCLOSE|
-+ WDIOF_KEEPALIVEPING,
-+ .firmware_version = 1,
-+ .identity = "BCM2708",
-+ };
-+
-+ switch (cmd) {
-+ case WDIOC_GETSUPPORT:
-+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-+ case WDIOC_GETSTATUS:
-+ status = wdog_get_status();
-+ return put_user(status, p);
-+ case WDIOC_GETBOOTSTATUS:
-+ return put_user(0, p);
-+ case WDIOC_KEEPALIVE:
-+ wdog_ping();
-+ return 0;
-+ case WDIOC_SETTIMEOUT:
-+ if (get_user(new_heartbeat, p))
-+ return -EFAULT;
-+ if (wdog_set_heartbeat(new_heartbeat))
-+ return -EINVAL;
-+ wdog_ping();
-+ /* Fall */
-+ case WDIOC_GETTIMEOUT:
-+ return put_user(heartbeat, p);
-+ case WDIOC_GETTIMELEFT:
-+ remaining = WDOG_TICKS_TO_SECS(wdog_get_remaining());
-+ return put_user(remaining, p);
-+ case WDIOC_SETOPTIONS:
-+ if (get_user(options, p))
-+ return -EFAULT;
-+ if (options & WDIOS_DISABLECARD)
-+ wdog_stop();
-+ if (options & WDIOS_ENABLECARD)
-+ wdog_start(wdog_ticks);
-+ return 0;
-+ default:
-+ return -ENOTTY;
-+ }
-+}
-+
-+/**
-+ * @inode: inode of device
-+ * @file: file handle to device
-+ *
-+ * The watchdog device has been opened. The watchdog device is single
-+ * open and on opening we load the counters.
-+ */
-+
-+static int wdog_open(struct inode *inode, struct file *file)
-+{
-+ if (test_and_set_bit(0, &wdog_is_open))
-+ return -EBUSY;
-+ /*
-+ * Activate
-+ */
-+ wdog_start(wdog_ticks);
-+ return nonseekable_open(inode, file);
-+}
-+
-+/**
-+ * @inode: inode to board
-+ * @file: file handle to board
-+ *
-+ * The watchdog has a configurable API. There is a religious dispute
-+ * between people who want their watchdog to be able to shut down and
-+ * those who want to be sure if the watchdog manager dies the machine
-+ * reboots. In the former case we disable the counters, in the latter
-+ * case you have to open it again very soon.
-+ */
-+
-+static int wdog_release(struct inode *inode, struct file *file)
-+{
-+ if (expect_close == 42) {
-+ wdog_stop();
-+ } else {
-+ printk(KERN_CRIT
-+ "wdt: WDT device closed unexpectedly. WDT will not stop!\n");
-+ wdog_ping();
-+ }
-+ clear_bit(0, &wdog_is_open);
-+ expect_close = 0;
-+ return 0;
-+}
-+
-+/**
-+ * @this: our notifier block
-+ * @code: the event being reported
-+ * @unused: unused
-+ *
-+ * Our notifier is called on system shutdowns. Turn the watchdog
-+ * off so that it does not fire during the next reboot.
-+ */
-+
-+static int wdog_notify_sys(struct notifier_block *this, unsigned long code,
-+ void *unused)
-+{
-+ if (code == SYS_DOWN || code == SYS_HALT)
-+ wdog_stop();
-+ return NOTIFY_DONE;
-+}
-+
-+/*
-+ * Kernel Interfaces
-+ */
-+
-+
-+static const struct file_operations wdog_fops = {
-+ .owner = THIS_MODULE,
-+ .llseek = no_llseek,
-+ .write = wdog_write,
-+ .unlocked_ioctl = wdog_ioctl,
-+ .open = wdog_open,
-+ .release = wdog_release,
-+};
-+
-+static struct miscdevice wdog_miscdev = {
-+ .minor = WATCHDOG_MINOR,
-+ .name = "watchdog",
-+ .fops = &wdog_fops,
-+};
-+
-+/*
-+ * The WDT card needs to learn about soft shutdowns in order to
-+ * turn the timebomb registers off.
-+ */
-+
-+static struct notifier_block wdog_notifier = {
-+ .notifier_call = wdog_notify_sys,
-+};
-+
-+/**
-+ * cleanup_module:
-+ *
-+ * Unload the watchdog. You cannot do this with any file handles open.
-+ * If your watchdog is set to continue ticking on close and you unload
-+ * it, well it keeps ticking. We won't get the interrupt but the board
-+ * will not touch PC memory so all is fine. You just have to load a new
-+ * module in 60 seconds or reboot.
-+ */
-+
-+static void __exit wdog_exit(void)
-+{
-+ misc_deregister(&wdog_miscdev);
-+ unregister_reboot_notifier(&wdog_notifier);
-+}
-+
-+static int __init wdog_init(void)
-+{
-+ int ret;
-+
-+ /* Check that the heartbeat value is within it's range;
-+ if not reset to the default */
-+ if (wdog_set_heartbeat(heartbeat)) {
-+ wdog_set_heartbeat(WD_TIMO);
-+ printk(KERN_INFO "bcm2708_wdog: heartbeat value must be "
-+ "0 < heartbeat < %d, using %d\n",
-+ WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
-+ WD_TIMO);
-+ }
-+
-+ ret = register_reboot_notifier(&wdog_notifier);
-+ if (ret) {
-+ printk(KERN_ERR
-+ "wdt: cannot register reboot notifier (err=%d)\n", ret);
-+ goto out_reboot;
-+ }
-+
-+ ret = misc_register(&wdog_miscdev);
-+ if (ret) {
-+ printk(KERN_ERR
-+ "wdt: cannot register miscdev on minor=%d (err=%d)\n",
-+ WATCHDOG_MINOR, ret);
-+ goto out_misc;
-+ }
-+
-+ printk(KERN_INFO "bcm2708 watchdog, heartbeat=%d sec (nowayout=%d)\n",
-+ heartbeat, nowayout);
-+ return 0;
-+
-+out_misc:
-+ unregister_reboot_notifier(&wdog_notifier);
-+out_reboot:
-+ return ret;
-+}
-+
-+module_init(wdog_init);
-+module_exit(wdog_exit);
-+
-+MODULE_AUTHOR("Luke Diamand");
-+MODULE_DESCRIPTION("Driver for BCM2708 watchdog");
-+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
-+MODULE_LICENSE("GPL");
-diff -Nur linux-3.11.10.orig/drivers/watchdog/Kconfig linux-3.11.10/drivers/watchdog/Kconfig
---- linux-3.11.10.orig/drivers/watchdog/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/watchdog/Kconfig 2014-02-07 19:57:30.000000000 +0100
-@@ -382,6 +382,12 @@
- To compile this driver as a module, choose M here: the
- module will be called retu_wdt.
-
-+config BCM2708_WDT
-+ tristate "BCM2708 Watchdog"
-+ depends on ARCH_BCM2708
-+ help
-+ Enables BCM2708 watchdog support.
-+
- # AVR32 Architecture
-
- config AT32AP700X_WDT
-diff -Nur linux-3.11.10.orig/drivers/watchdog/Makefile linux-3.11.10/drivers/watchdog/Makefile
---- linux-3.11.10.orig/drivers/watchdog/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/watchdog/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -53,6 +53,7 @@
- obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
- obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
- obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
-+obj-$(CONFIG_BCM2708_WDT) += bcm2708_wdog.o
- obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
-
- # AVR32 Architecture
-diff -Nur linux-3.11.10.orig/include/linux/broadcom/vc_cma.h linux-3.11.10/include/linux/broadcom/vc_cma.h
---- linux-3.11.10.orig/include/linux/broadcom/vc_cma.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/include/linux/broadcom/vc_cma.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,29 @@
-+/*****************************************************************************
-+* Copyright 2012 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#if !defined( VC_CMA_H )
-+#define VC_CMA_H
-+
-+#include <linux/ioctl.h>
-+
-+#define VC_CMA_IOC_MAGIC 0xc5
-+
-+#define VC_CMA_IOC_RESERVE _IO(VC_CMA_IOC_MAGIC, 0)
-+
-+#ifdef __KERNEL__
-+extern void __init vc_cma_early_init(void);
-+extern void __init vc_cma_reserve(void);
-+#endif
-+
-+#endif /* VC_CMA_H */
-diff -Nur linux-3.11.10.orig/include/linux/mmc/host.h linux-3.11.10/include/linux/mmc/host.h
---- linux-3.11.10.orig/include/linux/mmc/host.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/include/linux/mmc/host.h 2014-02-07 19:57:30.000000000 +0100
-@@ -281,6 +281,7 @@
- MMC_CAP2_PACKED_WR)
- #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
- #define MMC_CAP2_SANITIZE (1 << 15) /* Support Sanitize */
-+#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 31) /* Always use multiblock transfers */
-
- mmc_pm_flag_t pm_caps; /* supported pm features */
-
-diff -Nur linux-3.11.10.orig/include/linux/mmc/sdhci.h linux-3.11.10/include/linux/mmc/sdhci.h
---- linux-3.11.10.orig/include/linux/mmc/sdhci.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/include/linux/mmc/sdhci.h 2014-02-07 19:57:30.000000000 +0100
-@@ -100,6 +100,7 @@
- #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5)
-
- int irq; /* Device IRQ */
-+ int second_irq; /* Additional IRQ to disable/enable in low-latency mode */
- void __iomem *ioaddr; /* Mapped address */
-
- const struct sdhci_ops *ops; /* Low level hw interface */
-@@ -131,6 +132,7 @@
- #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
- #define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
- #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
-+#define SDHCI_USE_PLATDMA (1<<12) /* Host uses 3rd party DMA */
-
- unsigned int version; /* SDHCI spec. version */
-
-@@ -146,6 +148,7 @@
-
- struct mmc_request *mrq; /* Current request */
- struct mmc_command *cmd; /* Current command */
-+ int last_cmdop; /* Opcode of last cmd sent */
- struct mmc_data *data; /* Current data request */
- unsigned int data_early:1; /* Data finished before cmd */
-
-diff -Nur linux-3.11.10.orig/include/uapi/linux/fb.h linux-3.11.10/include/uapi/linux/fb.h
---- linux-3.11.10.orig/include/uapi/linux/fb.h 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/include/uapi/linux/fb.h 2014-02-07 19:57:30.000000000 +0100
-@@ -34,6 +34,11 @@
- #define FBIOPUT_MODEINFO 0x4617
- #define FBIOGET_DISPINFO 0x4618
- #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-+/*
-+ * HACK: use 'z' in order not to clash with any other ioctl numbers which might
-+ * be concurrently added to the mainline kernel
-+ */
-+#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea)
-
- #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
- #define FB_TYPE_PLANES 1 /* Non interleaved planes */
-diff -Nur linux-3.11.10.orig/sound/arm/bcm2835.c linux-3.11.10/sound/arm/bcm2835.c
---- linux-3.11.10.orig/sound/arm/bcm2835.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/sound/arm/bcm2835.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,413 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/platform_device.h>
-+
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+
-+#include "bcm2835.h"
-+
-+/* module parameters (see "Module Parameters") */
-+/* SNDRV_CARDS: maximum number of cards supported by this module */
-+static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
-+static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
-+static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
-+
-+/* HACKY global pointers needed for successive probes to work : ssp
-+ * But compared against the changes we will have to do in VC audio_ipc code
-+ * to export 8 audio_ipc devices as a single IPC device and then monitor all
-+ * four devices in a thread, this gets things done quickly and should be easier
-+ * to debug if we run into issues
-+ */
-+
-+static struct snd_card *g_card = NULL;
-+static bcm2835_chip_t *g_chip = NULL;
-+
-+static int snd_bcm2835_free(bcm2835_chip_t * chip)
-+{
-+ kfree(chip);
-+ return 0;
-+}
-+
-+/* component-destructor
-+ * (see "Management of Cards and Components")
-+ */
-+static int snd_bcm2835_dev_free(struct snd_device *device)
-+{
-+ return snd_bcm2835_free(device->device_data);
-+}
-+
-+/* chip-specific constructor
-+ * (see "Management of Cards and Components")
-+ */
-+static int snd_bcm2835_create(struct snd_card *card,
-+ struct platform_device *pdev,
-+ bcm2835_chip_t ** rchip)
-+{
-+ bcm2835_chip_t *chip;
-+ int err;
-+ static struct snd_device_ops ops = {
-+ .dev_free = snd_bcm2835_dev_free,
-+ };
-+
-+ *rchip = NULL;
-+
-+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-+ if (chip == NULL)
-+ return -ENOMEM;
-+
-+ chip->card = card;
-+
-+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
-+ if (err < 0) {
-+ snd_bcm2835_free(chip);
-+ return err;
-+ }
-+
-+ *rchip = chip;
-+ return 0;
-+}
-+
-+static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
-+{
-+ static int dev;
-+ bcm2835_chip_t *chip;
-+ struct snd_card *card;
-+ int err;
-+
-+ if (dev >= MAX_SUBSTREAMS)
-+ return -ENODEV;
-+
-+ if (!enable[dev]) {
-+ dev++;
-+ return -ENOENT;
-+ }
-+
-+ if (dev > 0)
-+ goto add_register_map;
-+
-+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
-+ if (err < 0)
-+ goto out;
-+
-+ snd_card_set_dev(g_card, &pdev->dev);
-+ strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver");
-+ strcpy(g_card->shortname, "bcm2835 ALSA");
-+ sprintf(g_card->longname, "%s", g_card->shortname);
-+
-+ err = snd_bcm2835_create(g_card, pdev, &chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
-+ goto out_bcm2835_create;
-+ }
-+
-+ g_chip = chip;
-+ err = snd_bcm2835_new_pcm(chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
-+ goto out_bcm2835_new_pcm;
-+ }
-+
-+ err = snd_bcm2835_new_ctl(chip);
-+ if (err < 0) {
-+ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
-+ goto out_bcm2835_new_ctl;
-+ }
-+
-+add_register_map:
-+ card = g_card;
-+ chip = g_chip;
-+
-+ BUG_ON(!(card && chip));
-+
-+ chip->avail_substreams |= (1 << dev);
-+ chip->pdev[dev] = pdev;
-+
-+ if (dev == 0) {
-+ err = snd_card_register(card);
-+ if (err < 0) {
-+ dev_err(&pdev->dev,
-+ "Failed to register bcm2835 ALSA card \n");
-+ goto out_card_register;
-+ }
-+ platform_set_drvdata(pdev, card);
-+ audio_info("bcm2835 ALSA card created!\n");
-+ } else {
-+ audio_info("bcm2835 ALSA chip created!\n");
-+ platform_set_drvdata(pdev, (void *)dev);
-+ }
-+
-+ dev++;
-+
-+ return 0;
-+
-+out_card_register:
-+out_bcm2835_new_ctl:
-+out_bcm2835_new_pcm:
-+out_bcm2835_create:
-+ BUG_ON(!g_card);
-+ if (snd_card_free(g_card))
-+ dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
-+ g_card = NULL;
-+out:
-+ dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
-+ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
-+ return err;
-+}
-+
-+static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
-+{
-+ uint32_t idx;
-+ void *drv_data;
-+
-+ drv_data = platform_get_drvdata(pdev);
-+
-+ if (drv_data == (void *)g_card) {
-+ /* This is the card device */
-+ snd_card_free((struct snd_card *)drv_data);
-+ g_card = NULL;
-+ g_chip = NULL;
-+ } else {
-+ idx = (uint32_t) drv_data;
-+ if (g_card != NULL) {
-+ BUG_ON(!g_chip);
-+ /* We pass chip device numbers in audio ipc devices
-+ * other than the one we registered our card with
-+ */
-+ idx = (uint32_t) drv_data;
-+ BUG_ON(!idx || idx > MAX_SUBSTREAMS);
-+ g_chip->avail_substreams &= ~(1 << idx);
-+ /* There should be atleast one substream registered
-+ * after we are done here, as it wil be removed when
-+ * the *remove* is called for the card device
-+ */
-+ BUG_ON(!g_chip->avail_substreams);
-+ }
-+ }
-+
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
-+ pm_message_t state)
-+{
-+ return 0;
-+}
-+
-+static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+#endif
-+
-+static struct platform_driver bcm2835_alsa0_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD0",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa1_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD1",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa2_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD2",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa3_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD3",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa4_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD4",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa5_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD5",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa6_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD6",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static struct platform_driver bcm2835_alsa7_driver = {
-+ .probe = snd_bcm2835_alsa_probe,
-+ .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+ .suspend = snd_bcm2835_alsa_suspend,
-+ .resume = snd_bcm2835_alsa_resume,
-+#endif
-+ .driver = {
-+ .name = "bcm2835_AUD7",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int bcm2835_alsa_device_init(void)
-+{
-+ int err;
-+ err = platform_driver_register(&bcm2835_alsa0_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto out;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa1_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_0;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa2_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_1;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa3_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_2;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa4_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_3;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa5_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_4;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa6_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_5;
-+ }
-+
-+ err = platform_driver_register(&bcm2835_alsa7_driver);
-+ if (err) {
-+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
-+ goto unregister_6;
-+ }
-+
-+ return 0;
-+
-+unregister_6:
-+ platform_driver_unregister(&bcm2835_alsa6_driver);
-+unregister_5:
-+ platform_driver_unregister(&bcm2835_alsa5_driver);
-+unregister_4:
-+ platform_driver_unregister(&bcm2835_alsa4_driver);
-+unregister_3:
-+ platform_driver_unregister(&bcm2835_alsa3_driver);
-+unregister_2:
-+ platform_driver_unregister(&bcm2835_alsa2_driver);
-+unregister_1:
-+ platform_driver_unregister(&bcm2835_alsa1_driver);
-+unregister_0:
-+ platform_driver_unregister(&bcm2835_alsa0_driver);
-+out:
-+ return err;
-+}
-+
-+static void bcm2835_alsa_device_exit(void)
-+{
-+ platform_driver_unregister(&bcm2835_alsa0_driver);
-+ platform_driver_unregister(&bcm2835_alsa1_driver);
-+ platform_driver_unregister(&bcm2835_alsa2_driver);
-+ platform_driver_unregister(&bcm2835_alsa3_driver);
-+ platform_driver_unregister(&bcm2835_alsa4_driver);
-+ platform_driver_unregister(&bcm2835_alsa5_driver);
-+ platform_driver_unregister(&bcm2835_alsa6_driver);
-+ platform_driver_unregister(&bcm2835_alsa7_driver);
-+}
-+
-+late_initcall(bcm2835_alsa_device_init);
-+module_exit(bcm2835_alsa_device_exit);
-+
-+MODULE_AUTHOR("Dom Cobley");
-+MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:bcm2835_alsa");
-diff -Nur linux-3.11.10.orig/sound/arm/bcm2835-ctl.c linux-3.11.10/sound/arm/bcm2835-ctl.c
---- linux-3.11.10.orig/sound/arm/bcm2835-ctl.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/sound/arm/bcm2835-ctl.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,200 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/platform_device.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/jiffies.h>
-+#include <linux/slab.h>
-+#include <linux/time.h>
-+#include <linux/wait.h>
-+#include <linux/delay.h>
-+#include <linux/moduleparam.h>
-+#include <linux/sched.h>
-+
-+#include <sound/core.h>
-+#include <sound/control.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/rawmidi.h>
-+#include <sound/initval.h>
-+#include <sound/tlv.h>
-+
-+#include "bcm2835.h"
-+
-+/* volume maximum and minimum in terms of 0.01dB */
-+#define CTRL_VOL_MAX 400
-+#define CTRL_VOL_MIN -10239 /* originally -10240 */
-+
-+
-+static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_info *uinfo)
-+{
-+ audio_info(" ... IN\n");
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = CTRL_VOL_MIN;
-+ uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = 1;
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count = 1;
-+ uinfo->value.integer.min = 0;
-+ uinfo->value.integer.max = AUDIO_DEST_MAX-1;
-+ }
-+ audio_info(" ... OUT\n");
-+ return 0;
-+}
-+
-+/* toggles mute on or off depending on the value of nmute, and returns
-+ * 1 if the mute value was changed, otherwise 0
-+ */
-+static int toggle_mute(struct bcm2835_chip *chip, int nmute)
-+{
-+ /* if settings are ok, just return 0 */
-+ if(chip->mute == nmute)
-+ return 0;
-+
-+ /* if the sound is muted then we need to unmute */
-+ if(chip->mute == CTRL_VOL_MUTE)
-+ {
-+ chip->volume = chip->old_volume; /* copy the old volume back */
-+ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-+ }
-+ else /* otherwise we mute */
-+ {
-+ chip->old_volume = chip->volume;
-+ chip->volume = 26214; /* set volume to minimum level AKA mute */
-+ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-+ }
-+
-+ chip->mute = nmute;
-+ return 1;
-+}
-+
-+static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+
-+ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
-+
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
-+ ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
-+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
-+ ucontrol->value.integer.value[0] = chip->mute;
-+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
-+ ucontrol->value.integer.value[0] = chip->dest;
-+
-+ return 0;
-+}
-+
-+static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+ int changed = 0;
-+
-+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-+ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
-+ if (chip->mute == CTRL_VOL_MUTE) {
-+ /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
-+ return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
-+ }
-+ if (changed
-+ || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
-+
-+ chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
-+ changed = 1;
-+ }
-+
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-+ /* Now implemented */
-+ audio_info(" Mute attempted\n");
-+ changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
-+
-+ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-+ if (ucontrol->value.integer.value[0] != chip->dest) {
-+ chip->dest = ucontrol->value.integer.value[0];
-+ changed = 1;
-+ }
-+ }
-+
-+ if (changed) {
-+ if (bcm2835_audio_set_ctls(chip))
-+ printk(KERN_ERR "Failed to set ALSA controls..\n");
-+ }
-+
-+ return changed;
-+}
-+
-+static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
-+
-+static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "PCM Playback Volume",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+ .private_value = PCM_PLAYBACK_VOLUME,
-+ .info = snd_bcm2835_ctl_info,
-+ .get = snd_bcm2835_ctl_get,
-+ .put = snd_bcm2835_ctl_put,
-+ .count = 1,
-+ .tlv = {.p = snd_bcm2835_db_scale}
-+ },
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "PCM Playback Switch",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .private_value = PCM_PLAYBACK_MUTE,
-+ .info = snd_bcm2835_ctl_info,
-+ .get = snd_bcm2835_ctl_get,
-+ .put = snd_bcm2835_ctl_put,
-+ .count = 1,
-+ },
-+ {
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .name = "PCM Playback Route",
-+ .index = 0,
-+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .private_value = PCM_PLAYBACK_DEVICE,
-+ .info = snd_bcm2835_ctl_info,
-+ .get = snd_bcm2835_ctl_get,
-+ .put = snd_bcm2835_ctl_put,
-+ .count = 1,
-+ },
-+};
-+
-+int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
-+{
-+ int err;
-+ unsigned int idx;
-+
-+ strcpy(chip->card->mixername, "Broadcom Mixer");
-+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
-+ err =
-+ snd_ctl_add(chip->card,
-+ snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
-+ if (err < 0)
-+ return err;
-+ }
-+ return 0;
-+}
-diff -Nur linux-3.11.10.orig/sound/arm/bcm2835.h linux-3.11.10/sound/arm/bcm2835.h
---- linux-3.11.10.orig/sound/arm/bcm2835.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/sound/arm/bcm2835.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,157 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef __SOUND_ARM_BCM2835_H
-+#define __SOUND_ARM_BCM2835_H
-+
-+#include <linux/device.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/wait.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/pcm-indirect.h>
-+#include <linux/workqueue.h>
-+
-+/*
-+#define AUDIO_DEBUG_ENABLE
-+#define AUDIO_VERBOSE_DEBUG_ENABLE
-+*/
-+
-+/* Debug macros */
-+
-+#ifdef AUDIO_DEBUG_ENABLE
-+#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
-+
-+#define audio_debug(fmt, arg...) \
-+ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_info(fmt, arg...) \
-+ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#else
-+
-+#define audio_debug(fmt, arg...)
-+
-+#define audio_info(fmt, arg...)
-+
-+#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
-+
-+#else
-+
-+#define audio_debug(fmt, arg...)
-+
-+#define audio_info(fmt, arg...)
-+
-+#endif /* AUDIO_DEBUG_ENABLE */
-+
-+#define audio_error(fmt, arg...) \
-+ printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_warning(fmt, arg...) \
-+ printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_alert(fmt, arg...) \
-+ printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define MAX_SUBSTREAMS (8)
-+#define AVAIL_SUBSTREAMS_MASK (0xff)
-+enum {
-+ CTRL_VOL_MUTE,
-+ CTRL_VOL_UNMUTE
-+};
-+
-+/* macros for alsa2chip and chip2alsa, instead of functions */
-+
-+#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
-+#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
-+
-+/* Some constants for values .. */
-+typedef enum {
-+ AUDIO_DEST_AUTO = 0,
-+ AUDIO_DEST_HEADPHONES = 1,
-+ AUDIO_DEST_HDMI = 2,
-+ AUDIO_DEST_MAX,
-+} SND_BCM2835_ROUTE_T;
-+
-+typedef enum {
-+ PCM_PLAYBACK_VOLUME,
-+ PCM_PLAYBACK_MUTE,
-+ PCM_PLAYBACK_DEVICE,
-+} SND_BCM2835_CTRL_T;
-+
-+/* definition of the chip-specific record */
-+typedef struct bcm2835_chip {
-+ struct snd_card *card;
-+ struct snd_pcm *pcm;
-+ /* Bitmat for valid reg_base and irq numbers */
-+ uint32_t avail_substreams;
-+ struct platform_device *pdev[MAX_SUBSTREAMS];
-+ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
-+
-+ int volume;
-+ int old_volume; /* stores the volume value whist muted */
-+ int dest;
-+ int mute;
-+} bcm2835_chip_t;
-+
-+typedef struct bcm2835_alsa_stream {
-+ bcm2835_chip_t *chip;
-+ struct snd_pcm_substream *substream;
-+ struct snd_pcm_indirect pcm_indirect;
-+
-+ struct semaphore buffers_update_sem;
-+ struct semaphore control_sem;
-+ spinlock_t lock;
-+ volatile uint32_t control;
-+ volatile uint32_t status;
-+
-+ int open;
-+ int running;
-+ int draining;
-+
-+ unsigned int pos;
-+ unsigned int buffer_size;
-+ unsigned int period_size;
-+
-+ uint32_t enable_fifo_irq;
-+ irq_handler_t fifo_irq_handler;
-+
-+ atomic_t retrieved;
-+ struct opaque_AUDIO_INSTANCE_T *instance;
-+ struct workqueue_struct *my_wq;
-+ int idx;
-+} bcm2835_alsa_stream_t;
-+
-+int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
-+int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
-+
-+int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
-+ uint32_t channels, uint32_t samplerate,
-+ uint32_t bps);
-+int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
-+int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
-+ void *src);
-+uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+
-+#endif /* __SOUND_ARM_BCM2835_H */
-diff -Nur linux-3.11.10.orig/sound/arm/bcm2835-pcm.c linux-3.11.10/sound/arm/bcm2835-pcm.c
---- linux-3.11.10.orig/sound/arm/bcm2835-pcm.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/sound/arm/bcm2835-pcm.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,426 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+
-+#include "bcm2835.h"
-+
-+/* hardware definition */
-+static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
-+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-+ .rate_min = 8000,
-+ .rate_max = 48000,
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .buffer_bytes_max = 128 * 1024,
-+ .period_bytes_min = 1 * 1024,
-+ .period_bytes_max = 128 * 1024,
-+ .periods_min = 1,
-+ .periods_max = 128,
-+};
-+
-+static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
-+{
-+ audio_info("Freeing up alsa stream here ..\n");
-+ if (runtime->private_data)
-+ kfree(runtime->private_data);
-+ runtime->private_data = NULL;
-+}
-+
-+static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
-+{
-+ bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
-+ uint32_t consumed = 0;
-+ int new_period = 0;
-+
-+ audio_info(" .. IN\n");
-+
-+ audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
-+ alsa_stream ? alsa_stream->substream : 0);
-+
-+ if (alsa_stream->open)
-+ consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
-+
-+ /* We get called only if playback was triggered, So, the number of buffers we retrieve in
-+ * each iteration are the buffers that have been played out already
-+ */
-+
-+ if (alsa_stream->period_size) {
-+ if ((alsa_stream->pos / alsa_stream->period_size) !=
-+ ((alsa_stream->pos + consumed) / alsa_stream->period_size))
-+ new_period = 1;
-+ }
-+ audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
-+ alsa_stream->pos,
-+ consumed,
-+ alsa_stream->buffer_size,
-+ (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
-+ frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
-+ new_period);
-+ if (alsa_stream->buffer_size) {
-+ alsa_stream->pos += consumed &~ (1<<30);
-+ alsa_stream->pos %= alsa_stream->buffer_size;
-+ }
-+
-+ if (alsa_stream->substream) {
-+ if (new_period)
-+ snd_pcm_period_elapsed(alsa_stream->substream);
-+ } else {
-+ audio_warning(" unexpected NULL substream\n");
-+ }
-+ audio_info(" .. OUT\n");
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/* open callback */
-+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
-+{
-+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+ int idx;
-+ int err;
-+
-+ audio_info(" .. IN (%d)\n", substream->number);
-+
-+ audio_info("Alsa open (%d)\n", substream->number);
-+ idx = substream->number;
-+
-+ if (idx > MAX_SUBSTREAMS) {
-+ audio_error
-+ ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
-+ idx, MAX_SUBSTREAMS);
-+ err = -ENODEV;
-+ goto out;
-+ }
-+
-+ /* Check if we are ready */
-+ if (!(chip->avail_substreams & (1 << idx))) {
-+ /* We are not ready yet */
-+ audio_error("substream(%d) device is not ready yet\n", idx);
-+ err = -EAGAIN;
-+ goto out;
-+ }
-+
-+ alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
-+ if (alsa_stream == NULL) {
-+ return -ENOMEM;
-+ }
-+
-+ /* Initialise alsa_stream */
-+ alsa_stream->chip = chip;
-+ alsa_stream->substream = substream;
-+ alsa_stream->idx = idx;
-+ chip->alsa_stream[idx] = alsa_stream;
-+
-+ sema_init(&alsa_stream->buffers_update_sem, 0);
-+ sema_init(&alsa_stream->control_sem, 0);
-+ spin_lock_init(&alsa_stream->lock);
-+
-+ /* Enabled in start trigger, called on each "fifo irq" after that */
-+ alsa_stream->enable_fifo_irq = 0;
-+ alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
-+
-+ runtime->private_data = alsa_stream;
-+ runtime->private_free = snd_bcm2835_playback_free;
-+ runtime->hw = snd_bcm2835_playback_hw;
-+ /* minimum 16 bytes alignment (for vchiq bulk transfers) */
-+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-+ 16);
-+
-+ err = bcm2835_audio_open(alsa_stream);
-+ if (err != 0) {
-+ kfree(alsa_stream);
-+ return err;
-+ }
-+
-+ alsa_stream->open = 1;
-+ alsa_stream->draining = 1;
-+
-+out:
-+ audio_info(" .. OUT =%d\n", err);
-+
-+ return err;
-+}
-+
-+/* close callback */
-+static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
-+{
-+ /* the hardware-specific codes will be here */
-+
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+ audio_info(" .. IN\n");
-+ audio_info("Alsa close\n");
-+
-+ /*
-+ * Call stop if it's still running. This happens when app
-+ * is force killed and we don't get a stop trigger.
-+ */
-+ if (alsa_stream->running) {
-+ int err;
-+ err = bcm2835_audio_stop(alsa_stream);
-+ alsa_stream->running = 0;
-+ if (err != 0)
-+ audio_error(" Failed to STOP alsa device\n");
-+ }
-+
-+ alsa_stream->period_size = 0;
-+ alsa_stream->buffer_size = 0;
-+
-+ if (alsa_stream->open) {
-+ alsa_stream->open = 0;
-+ bcm2835_audio_close(alsa_stream);
-+ }
-+ if (alsa_stream->chip)
-+ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
-+ /*
-+ * Do not free up alsa_stream here, it will be freed up by
-+ * runtime->private_free callback we registered in *_open above
-+ */
-+
-+ audio_info(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+/* hw_params callback */
-+static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ int err;
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream =
-+ (bcm2835_alsa_stream_t *) runtime->private_data;
-+
-+ audio_info(" .. IN\n");
-+
-+ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-+ if (err < 0) {
-+ audio_error
-+ (" pcm_lib_malloc failed to allocated pages for buffers\n");
-+ return err;
-+ }
-+
-+ err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
-+ params_rate(params),
-+ snd_pcm_format_width(params_format
-+ (params)));
-+ if (err < 0) {
-+ audio_error(" error setting hw params\n");
-+ }
-+
-+ bcm2835_audio_setup(alsa_stream);
-+
-+ /* in preparation of the stream, set the controls (volume level) of the stream */
-+ bcm2835_audio_set_ctls(alsa_stream->chip);
-+
-+ audio_info(" .. OUT\n");
-+
-+ return err;
-+}
-+
-+/* hw_free callback */
-+static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+ audio_info(" .. IN\n");
-+ return snd_pcm_lib_free_pages(substream);
-+}
-+
-+/* prepare callback */
-+static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+ audio_info(" .. IN\n");
-+
-+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
-+
-+ alsa_stream->pcm_indirect.hw_buffer_size =
-+ alsa_stream->pcm_indirect.sw_buffer_size =
-+ snd_pcm_lib_buffer_bytes(substream);
-+
-+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
-+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
-+ alsa_stream->pos = 0;
-+
-+ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
-+ alsa_stream->buffer_size, alsa_stream->period_size,
-+ alsa_stream->pos, runtime->frame_bits);
-+
-+ audio_info(" .. OUT\n");
-+ return 0;
-+}
-+
-+static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
-+ struct snd_pcm_indirect *rec, size_t bytes)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
-+ int err;
-+
-+ err = bcm2835_audio_write(alsa_stream, bytes, src);
-+ if (err)
-+ audio_error(" Failed to transfer to alsa device (%d)\n", err);
-+
-+}
-+
-+static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
-+
-+ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
-+ snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
-+ snd_bcm2835_pcm_transfer);
-+ return 0;
-+}
-+
-+/* trigger callback */
-+static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+ int err = 0;
-+
-+ audio_info(" .. IN\n");
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
-+ alsa_stream->running);
-+ if (!alsa_stream->running) {
-+ err = bcm2835_audio_start(alsa_stream);
-+ if (err == 0) {
-+ alsa_stream->pcm_indirect.hw_io =
-+ alsa_stream->pcm_indirect.hw_data =
-+ bytes_to_frames(runtime,
-+ alsa_stream->pos);
-+ substream->ops->ack(substream);
-+ alsa_stream->running = 1;
-+ alsa_stream->draining = 1;
-+ } else {
-+ audio_error(" Failed to START alsa device (%d)\n", err);
-+ }
-+ }
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ audio_debug
-+ ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
-+ alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
-+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
-+ audio_info("DRAINING\n");
-+ alsa_stream->draining = 1;
-+ } else {
-+ audio_info("DROPPING\n");
-+ alsa_stream->draining = 0;
-+ }
-+ if (alsa_stream->running) {
-+ err = bcm2835_audio_stop(alsa_stream);
-+ if (err != 0)
-+ audio_error(" Failed to STOP alsa device (%d)\n", err);
-+ alsa_stream->running = 0;
-+ }
-+ break;
-+ default:
-+ err = -EINVAL;
-+ }
-+
-+ audio_info(" .. OUT\n");
-+ return err;
-+}
-+
-+/* pointer callback */
-+static snd_pcm_uframes_t
-+snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+ audio_info(" .. IN\n");
-+
-+ audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
-+ frames_to_bytes(runtime, runtime->status->hw_ptr),
-+ frames_to_bytes(runtime, runtime->control->appl_ptr),
-+ alsa_stream->pos);
-+
-+ audio_info(" .. OUT\n");
-+ return snd_pcm_indirect_playback_pointer(substream,
-+ &alsa_stream->pcm_indirect,
-+ alsa_stream->pos);
-+}
-+
-+static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
-+ unsigned int cmd, void *arg)
-+{
-+ int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
-+ audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
-+ cmd, arg, arg ? *(unsigned *)arg : 0, ret);
-+ return ret;
-+}
-+
-+/* operators */
-+static struct snd_pcm_ops snd_bcm2835_playback_ops = {
-+ .open = snd_bcm2835_playback_open,
-+ .close = snd_bcm2835_playback_close,
-+ .ioctl = snd_bcm2835_pcm_lib_ioctl,
-+ .hw_params = snd_bcm2835_pcm_hw_params,
-+ .hw_free = snd_bcm2835_pcm_hw_free,
-+ .prepare = snd_bcm2835_pcm_prepare,
-+ .trigger = snd_bcm2835_pcm_trigger,
-+ .pointer = snd_bcm2835_pcm_pointer,
-+ .ack = snd_bcm2835_pcm_ack,
-+};
-+
-+/* create a pcm device */
-+int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
-+{
-+ struct snd_pcm *pcm;
-+ int err;
-+
-+ audio_info(" .. IN\n");
-+ err =
-+ snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
-+ if (err < 0)
-+ return err;
-+ pcm->private_data = chip;
-+ strcpy(pcm->name, "bcm2835 ALSA");
-+ chip->pcm = pcm;
-+ chip->dest = AUDIO_DEST_AUTO;
-+ chip->volume = alsa2chip(0);
-+ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
-+ /* set operators */
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-+ &snd_bcm2835_playback_ops);
-+
-+ /* pre-allocation of buffers */
-+ /* NOTE: this may fail */
-+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-+ snd_dma_continuous_data
-+ (GFP_KERNEL), 64 * 1024,
-+ 64 * 1024);
-+
-+ audio_info(" .. OUT\n");
-+
-+ return 0;
-+}
-diff -Nur linux-3.11.10.orig/sound/arm/bcm2835-vchiq.c linux-3.11.10/sound/arm/bcm2835-vchiq.c
---- linux-3.11.10.orig/sound/arm/bcm2835-vchiq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/sound/arm/bcm2835-vchiq.c 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,879 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/device.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <linux/io.h>
-+#include <linux/interrupt.h>
-+#include <linux/fs.h>
-+#include <linux/file.h>
-+#include <linux/mm.h>
-+#include <linux/syscalls.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/atomic.h>
-+#include <linux/module.h>
-+#include <linux/completion.h>
-+
-+#include "bcm2835.h"
-+
-+/* ---- Include Files -------------------------------------------------------- */
-+
-+#include "interface/vchi/vchi.h"
-+#include "vc_vchi_audioserv_defs.h"
-+
-+/* ---- Private Constants and Types ------------------------------------------ */
-+
-+#define BCM2835_AUDIO_STOP 0
-+#define BCM2835_AUDIO_START 1
-+#define BCM2835_AUDIO_WRITE 2
-+
-+/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
-+#ifdef AUDIO_DEBUG_ENABLE
-+ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+#else
-+ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+ #define LOG_WARN( fmt, arg... )
-+ #define LOG_INFO( fmt, arg... )
-+ #define LOG_DBG( fmt, arg... )
-+#endif
-+
-+typedef struct opaque_AUDIO_INSTANCE_T {
-+ uint32_t num_connections;
-+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+ struct completion msg_avail_comp;
-+ struct mutex vchi_mutex;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+ int32_t result;
-+ short peer_version;
-+} AUDIO_INSTANCE_T;
-+
-+bool force_bulk = false;
-+
-+/* ---- Private Variables ---------------------------------------------------- */
-+
-+/* ---- Private Function Prototypes ------------------------------------------ */
-+
-+/* ---- Private Functions ---------------------------------------------------- */
-+
-+static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
-+static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
-+static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
-+ uint32_t count, void *src);
-+
-+typedef struct {
-+ struct work_struct my_work;
-+ bcm2835_alsa_stream_t *alsa_stream;
-+ int cmd;
-+ void *src;
-+ uint32_t count;
-+} my_work_t;
-+
-+static void my_wq_function(struct work_struct *work)
-+{
-+ my_work_t *w = (my_work_t *) work;
-+ int ret = -9;
-+ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
-+ switch (w->cmd) {
-+ case BCM2835_AUDIO_START:
-+ ret = bcm2835_audio_start_worker(w->alsa_stream);
-+ break;
-+ case BCM2835_AUDIO_STOP:
-+ ret = bcm2835_audio_stop_worker(w->alsa_stream);
-+ break;
-+ case BCM2835_AUDIO_WRITE:
-+ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
-+ w->src);
-+ break;
-+ default:
-+ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
-+ break;
-+ }
-+ kfree((void *)work);
-+ LOG_DBG(" .. OUT %d\n", ret);
-+}
-+
-+int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ int ret = -1;
-+ LOG_DBG(" .. IN\n");
-+ if (alsa_stream->my_wq) {
-+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+ /*--- Queue some work (item 1) ---*/
-+ if (work) {
-+ INIT_WORK((struct work_struct *)work, my_wq_function);
-+ work->alsa_stream = alsa_stream;
-+ work->cmd = BCM2835_AUDIO_START;
-+ if (queue_work
-+ (alsa_stream->my_wq, (struct work_struct *)work))
-+ ret = 0;
-+ } else
-+ LOG_ERR(" .. Error: NULL work kmalloc\n");
-+ }
-+ LOG_DBG(" .. OUT %d\n", ret);
-+ return ret;
-+}
-+
-+int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ int ret = -1;
-+ LOG_DBG(" .. IN\n");
-+ if (alsa_stream->my_wq) {
-+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+ /*--- Queue some work (item 1) ---*/
-+ if (work) {
-+ INIT_WORK((struct work_struct *)work, my_wq_function);
-+ work->alsa_stream = alsa_stream;
-+ work->cmd = BCM2835_AUDIO_STOP;
-+ if (queue_work
-+ (alsa_stream->my_wq, (struct work_struct *)work))
-+ ret = 0;
-+ } else
-+ LOG_ERR(" .. Error: NULL work kmalloc\n");
-+ }
-+ LOG_DBG(" .. OUT %d\n", ret);
-+ return ret;
-+}
-+
-+int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
-+ uint32_t count, void *src)
-+{
-+ int ret = -1;
-+ LOG_DBG(" .. IN\n");
-+ if (alsa_stream->my_wq) {
-+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+ /*--- Queue some work (item 1) ---*/
-+ if (work) {
-+ INIT_WORK((struct work_struct *)work, my_wq_function);
-+ work->alsa_stream = alsa_stream;
-+ work->cmd = BCM2835_AUDIO_WRITE;
-+ work->src = src;
-+ work->count = count;
-+ if (queue_work
-+ (alsa_stream->my_wq, (struct work_struct *)work))
-+ ret = 0;
-+ } else
-+ LOG_ERR(" .. Error: NULL work kmalloc\n");
-+ }
-+ LOG_DBG(" .. OUT %d\n", ret);
-+ return ret;
-+}
-+
-+void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ alsa_stream->my_wq = create_workqueue("my_queue");
-+ return;
-+}
-+
-+void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ if (alsa_stream->my_wq) {
-+ flush_workqueue(alsa_stream->my_wq);
-+ destroy_workqueue(alsa_stream->my_wq);
-+ alsa_stream->my_wq = NULL;
-+ }
-+ return;
-+}
-+
-+static void audio_vchi_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *msg_handle)
-+{
-+ AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
-+ int32_t status;
-+ int32_t msg_len;
-+ VC_AUDIO_MSG_T m;
-+ bcm2835_alsa_stream_t *alsa_stream = 0;
-+ LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n",
-+ instance, param, reason, msg_handle);
-+
-+ if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) {
-+ return;
-+ }
-+ alsa_stream = instance->alsa_stream;
-+ status = vchi_msg_dequeue(instance->vchi_handle[0],
-+ &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
-+ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
-+ LOG_DBG
-+ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
-+ instance, m.u.result.success);
-+ instance->result = m.u.result.success;
-+ complete(&instance->msg_avail_comp);
-+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
-+ irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
-+ LOG_DBG
-+ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
-+ instance, m.u.complete.count);
-+ if (alsa_stream && callback) {
-+ atomic_add(m.u.complete.count, &alsa_stream->retrieved);
-+ callback(0, alsa_stream);
-+ } else {
-+ LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n",
-+ alsa_stream, callback);
-+ }
-+ } else {
-+ LOG_DBG(" .. unexpected m.type=%d\n", m.type);
-+ }
-+ LOG_DBG(" .. OUT\n");
-+}
-+
-+static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
-+ VCHI_CONNECTION_T **
-+ vchi_connections,
-+ uint32_t num_connections)
-+{
-+ uint32_t i;
-+ AUDIO_INSTANCE_T *instance;
-+ int status;
-+
-+ LOG_DBG("%s: start", __func__);
-+
-+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-+ LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
-+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-+
-+ return NULL;
-+ }
-+ /* Allocate memory for this instance */
-+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
-+
-+ memset(instance, 0, sizeof(*instance));
-+ instance->num_connections = num_connections;
-+
-+ /* Create a lock for exclusive, serialized VCHI connection access */
-+ mutex_init(&instance->vchi_mutex);
-+ /* Open the VCHI service connections */
-+ for (i = 0; i < num_connections; i++) {
-+ SERVICE_CREATION_T params = {
-+ VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-+ VC_AUDIO_SERVER_NAME, // 4cc service code
-+ vchi_connections[i], // passed in fn pointers
-+ 0, // rx fifo size (unused)
-+ 0, // tx fifo size (unused)
-+ audio_vchi_callback, // service callback
-+ instance, // service callback parameter
-+ 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
-+ 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
-+ 0 // want crc check on bulk transfers
-+ };
-+
-+ status = vchi_service_open(vchi_instance, &params,
-+ &instance->vchi_handle[i]);
-+ if (status) {
-+ LOG_ERR
-+ ("%s: failed to open VCHI service connection (status=%d)\n",
-+ __func__, status);
-+
-+ goto err_close_services;
-+ }
-+ /* Finished with the service for now */
-+ vchi_service_release(instance->vchi_handle[i]);
-+ }
-+
-+ return instance;
-+
-+err_close_services:
-+ for (i = 0; i < instance->num_connections; i++) {
-+ vchi_service_close(instance->vchi_handle[i]);
-+ }
-+
-+ kfree(instance);
-+
-+ return NULL;
-+}
-+
-+static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
-+{
-+ uint32_t i;
-+
-+ LOG_DBG(" .. IN\n");
-+
-+ if (instance == NULL) {
-+ LOG_ERR("%s: invalid handle %p\n", __func__, instance);
-+
-+ return -1;
-+ }
-+
-+ LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+
-+ /* Close all VCHI service connections */
-+ for (i = 0; i < instance->num_connections; i++) {
-+ int32_t success;
-+ LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
-+ vchi_service_use(instance->vchi_handle[i]);
-+
-+ success = vchi_service_close(instance->vchi_handle[i]);
-+ if (success != 0) {
-+ LOG_ERR
-+ ("%s: failed to close VCHI service connection (status=%d)\n",
-+ __func__, success);
-+ }
-+ }
-+
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ kfree(instance);
-+
-+ LOG_DBG(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ static VCHI_INSTANCE_T vchi_instance;
-+ static VCHI_CONNECTION_T *vchi_connection;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO("%s: start", __func__);
-+ //BUG_ON(instance);
-+ if (instance) {
-+ LOG_ERR("%s: VCHI instance already open (%p)\n",
-+ __func__, instance);
-+ instance->alsa_stream = alsa_stream;
-+ alsa_stream->instance = instance;
-+ ret = 0; // xxx todo -1;
-+ goto err_free_mem;
-+ }
-+
-+ /* Initialize and create a VCHI connection */
-+ ret = vchi_initialise(&vchi_instance);
-+ if (ret != 0) {
-+ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+ ret = vchi_connect(NULL, 0, vchi_instance);
-+ if (ret != 0) {
-+ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ /* Initialize an instance of the audio service */
-+ instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
-+
-+ if (instance == NULL /*|| audio_handle != instance */ ) {
-+ LOG_ERR("%s: failed to initialize audio service\n", __func__);
-+
-+ ret = -EPERM;
-+ goto err_free_mem;
-+ }
-+
-+ instance->alsa_stream = alsa_stream;
-+ alsa_stream->instance = instance;
-+
-+ LOG_DBG(" success !\n");
-+err_free_mem:
-+ LOG_DBG(" .. OUT\n");
-+
-+ return ret;
-+}
-+
-+int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ AUDIO_INSTANCE_T *instance;
-+ VC_AUDIO_MSG_T m;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ my_workqueue_init(alsa_stream);
-+
-+ ret = bcm2835_audio_open_connection(alsa_stream);
-+ if (ret != 0) {
-+ ret = -1;
-+ goto exit;
-+ }
-+ instance = alsa_stream->instance;
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_OPEN;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+exit:
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
-+ bcm2835_chip_t * chip)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO
-+ (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ instance->result = -1;
-+
-+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
-+ m.u.control.dest = chip->dest;
-+ m.u.control.volume = chip->volume;
-+
-+ /* Create the message available completion */
-+ init_completion(&instance->msg_avail_comp);
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ /* We are expecting a reply from the videocore */
-+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
-+ if (ret) {
-+ LOG_ERR("%s: failed on waiting for event (status=%d)\n",
-+ __func__, success);
-+ goto unlock;
-+ }
-+
-+ if (instance->result != 0) {
-+ LOG_ERR("%s: result=%d\n", __func__, instance->result);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
-+{
-+ int i;
-+ int ret = 0;
-+ LOG_DBG(" .. IN\n");
-+
-+ /* change ctls for all substreams */
-+ for (i = 0; i < MAX_SUBSTREAMS; i++) {
-+ if (chip->avail_substreams & (1 << i)) {
-+ if (!chip->alsa_stream[i])
-+ {
-+ LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
-+ ret = 0;
-+ }
-+ else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
-+ (chip->alsa_stream[i], chip) != 0)
-+ {
-+ LOG_DBG("Couldn't set the controls for stream %d\n", i);
-+ ret = -1;
-+ }
-+ else LOG_DBG(" Controls set for stream %d\n", i);
-+ }
-+ }
-+ LOG_DBG(" .. OUT ret=%d\n", ret);
-+ return ret;
-+}
-+
-+int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
-+ uint32_t channels, uint32_t samplerate,
-+ uint32_t bps)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO
-+ (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
-+ channels, samplerate, bps);
-+
-+ /* resend ctls - alsa_stream may not have been open when first send */
-+ ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
-+ if (ret != 0) {
-+ LOG_ERR(" Alsa controls not supported\n");
-+ return -EINVAL;
-+ }
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ instance->result = -1;
-+
-+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
-+ m.u.config.channels = channels;
-+ m.u.config.samplerate = samplerate;
-+ m.u.config.bps = bps;
-+
-+ /* Create the message available completion */
-+ init_completion(&instance->msg_avail_comp);
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ /* We are expecting a reply from the videocore */
-+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
-+ if (ret) {
-+ LOG_ERR("%s: failed on waiting for event (status=%d)\n",
-+ __func__, success);
-+ goto unlock;
-+ }
-+
-+ if (instance->result != 0) {
-+ LOG_ERR("%s: result=%d", __func__, instance->result);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_DBG(" .. OUT\n");
-+
-+ return 0;
-+}
-+
-+static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_START;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_STOP;
-+ m.u.stop.draining = alsa_stream->draining;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+ LOG_DBG(" .. IN\n");
-+
-+ my_workqueue_quit(alsa_stream);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
-+
-+ /* Create the message available completion */
-+ init_completion(&instance->msg_avail_comp);
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+ __func__, success);
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
-+ if (ret) {
-+ LOG_ERR("%s: failed on waiting for event (status=%d)",
-+ __func__, success);
-+ goto unlock;
-+ }
-+ if (instance->result != 0) {
-+ LOG_ERR("%s: failed result (status=%d)",
-+ __func__, instance->result);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+
-+ /* Stop the audio service */
-+ if (instance) {
-+ vc_vchi_audio_deinit(instance);
-+ alsa_stream->instance = NULL;
-+ }
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
-+ uint32_t count, void *src)
-+{
-+ VC_AUDIO_MSG_T m;
-+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+ int32_t success;
-+ int ret;
-+
-+ LOG_DBG(" .. IN\n");
-+
-+ LOG_INFO(" Writing %d bytes from %p\n", count, src);
-+
-+ if(mutex_lock_interruptible(&instance->vchi_mutex))
-+ {
-+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+ return -EINTR;
-+ }
-+ vchi_service_use(instance->vchi_handle[0]);
-+
-+ if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
-+ LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
-+ }
-+ m.type = VC_AUDIO_MSG_TYPE_WRITE;
-+ m.u.write.count = count;
-+ // old version uses bulk, new version uses control
-+ m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
-+ m.u.write.callback = alsa_stream->fifo_irq_handler;
-+ m.u.write.cookie = alsa_stream;
-+ m.u.write.silence = src == NULL;
-+
-+ /* Send the message to the videocore */
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ &m, sizeof m,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+ if (success != 0) {
-+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+ if (!m.u.write.silence) {
-+ if (m.u.write.max_packet == 0) {
-+ /* Send the message to the videocore */
-+ success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
-+ src, count,
-+ 0 *
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED
-+ +
-+ 1 *
-+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
-+ NULL);
-+ } else {
-+ while (count > 0) {
-+ int bytes = min((int)m.u.write.max_packet, (int)count);
-+ success = vchi_msg_queue(instance->vchi_handle[0],
-+ src, bytes,
-+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+ src = (char *)src + bytes;
-+ count -= bytes;
-+ }
-+ }
-+ if (success != 0) {
-+ LOG_ERR
-+ ("%s: failed on vchi_bulk_queue_transmit (status=%d)",
-+ __func__, success);
-+
-+ ret = -1;
-+ goto unlock;
-+ }
-+ }
-+ ret = 0;
-+
-+unlock:
-+ vchi_service_release(instance->vchi_handle[0]);
-+ mutex_unlock(&instance->vchi_mutex);
-+ LOG_DBG(" .. OUT\n");
-+ return ret;
-+}
-+
-+/**
-+ * Returns all buffers from arm->vc
-+ */
-+void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ LOG_DBG(" .. IN\n");
-+ LOG_DBG(" .. OUT\n");
-+ return;
-+}
-+
-+/**
-+ * Forces VC to flush(drop) its filled playback buffers and
-+ * return them the us. (VC->ARM)
-+ */
-+void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ LOG_DBG(" .. IN\n");
-+ LOG_DBG(" .. OUT\n");
-+}
-+
-+uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+ uint32_t count = atomic_read(&alsa_stream->retrieved);
-+ atomic_sub(count, &alsa_stream->retrieved);
-+ return count;
-+}
-+
-+module_param(force_bulk, bool, 0444);
-+MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
-diff -Nur linux-3.11.10.orig/sound/arm/Kconfig linux-3.11.10/sound/arm/Kconfig
---- linux-3.11.10.orig/sound/arm/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/sound/arm/Kconfig 2014-02-07 19:57:30.000000000 +0100
-@@ -39,5 +39,12 @@
- Say Y or M if you want to support any AC97 codec attached to
- the PXA2xx AC97 interface.
-
-+config SND_BCM2835
-+ tristate "BCM2835 ALSA driver"
-+ depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
-+ select SND_PCM
-+ help
-+ Say Y or M if you want to support BCM2835 Alsa pcm card driver
-+
- endif # SND_ARM
-
-diff -Nur linux-3.11.10.orig/sound/arm/Makefile linux-3.11.10/sound/arm/Makefile
---- linux-3.11.10.orig/sound/arm/Makefile 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/sound/arm/Makefile 2014-02-07 19:57:30.000000000 +0100
-@@ -14,3 +14,8 @@
-
- obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
- snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-+
-+obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
-+snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
-+
-+EXTRA_CFLAGS += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
-diff -Nur linux-3.11.10.orig/sound/arm/vc_vchi_audioserv_defs.h linux-3.11.10/sound/arm/vc_vchi_audioserv_defs.h
---- linux-3.11.10.orig/sound/arm/vc_vchi_audioserv_defs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.10/sound/arm/vc_vchi_audioserv_defs.h 2014-02-07 19:57:30.000000000 +0100
-@@ -0,0 +1,116 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation. All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef _VC_AUDIO_DEFS_H_
-+#define _VC_AUDIO_DEFS_H_
-+
-+#define VC_AUDIOSERV_MIN_VER 1
-+#define VC_AUDIOSERV_VER 2
-+
-+// FourCC code used for VCHI connection
-+#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
-+
-+// Maximum message length
-+#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
-+
-+// List of screens that are currently supported
-+// All message types supported for HOST->VC direction
-+typedef enum {
-+ VC_AUDIO_MSG_TYPE_RESULT, // Generic result
-+ VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
-+ VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
-+ VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
-+ VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
-+ VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
-+ VC_AUDIO_MSG_TYPE_START, // Configure audio
-+ VC_AUDIO_MSG_TYPE_STOP, // Configure audio
-+ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
-+ VC_AUDIO_MSG_TYPE_MAX
-+} VC_AUDIO_MSG_TYPE;
-+
-+// configure the audio
-+typedef struct {
-+ uint32_t channels;
-+ uint32_t samplerate;
-+ uint32_t bps;
-+
-+} VC_AUDIO_CONFIG_T;
-+
-+typedef struct {
-+ uint32_t volume;
-+ uint32_t dest;
-+
-+} VC_AUDIO_CONTROL_T;
-+
-+// audio
-+typedef struct {
-+ uint32_t dummy;
-+
-+} VC_AUDIO_OPEN_T;
-+
-+// audio
-+typedef struct {
-+ uint32_t dummy;
-+
-+} VC_AUDIO_CLOSE_T;
-+// audio
-+typedef struct {
-+ uint32_t dummy;
-+
-+} VC_AUDIO_START_T;
-+// audio
-+typedef struct {
-+ uint32_t draining;
-+
-+} VC_AUDIO_STOP_T;
-+
-+// configure the write audio samples
-+typedef struct {
-+ uint32_t count; // in bytes
-+ void *callback;
-+ void *cookie;
-+ uint16_t silence;
-+ uint16_t max_packet;
-+} VC_AUDIO_WRITE_T;
-+
-+// Generic result for a request (VC->HOST)
-+typedef struct {
-+ int32_t success; // Success value
-+
-+} VC_AUDIO_RESULT_T;
-+
-+// Generic result for a request (VC->HOST)
-+typedef struct {
-+ int32_t count; // Success value
-+ void *callback;
-+ void *cookie;
-+} VC_AUDIO_COMPLETE_T;
-+
-+// Message header for all messages in HOST->VC direction
-+typedef struct {
-+ int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
-+ union {
-+ VC_AUDIO_CONFIG_T config;
-+ VC_AUDIO_CONTROL_T control;
-+ VC_AUDIO_OPEN_T open;
-+ VC_AUDIO_CLOSE_T close;
-+ VC_AUDIO_START_T start;
-+ VC_AUDIO_STOP_T stop;
-+ VC_AUDIO_WRITE_T write;
-+ VC_AUDIO_RESULT_T result;
-+ VC_AUDIO_COMPLETE_T complete;
-+ } u;
-+} VC_AUDIO_MSG_T;
-+
-+#endif // _VC_AUDIO_DEFS_H_
diff --git a/target/linux/patches/3.11.10/startup.patch b/target/linux/patches/3.11.10/startup.patch
deleted file mode 100644
index e7285873d..000000000
--- a/target/linux/patches/3.11.10/startup.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-diff -Nur linux-3.11.10.orig/init/initramfs.c linux-3.11.10/init/initramfs.c
---- linux-3.11.10.orig/init/initramfs.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/init/initramfs.c 2014-03-15 18:42:01.586249887 +0100
-@@ -622,6 +622,9 @@
- */
- load_default_modules();
- }
-+#ifdef CONFIG_DEVTMPFS_MOUNT
-+ devtmpfs_mount("dev");
-+#endif
- return 0;
- }
- rootfs_initcall(populate_rootfs);
-diff -Nur linux-3.11.10.orig/init/main.c linux-3.11.10/init/main.c
---- linux-3.11.10.orig/init/main.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/init/main.c 2014-03-15 18:42:01.590249897 +0100
-@@ -886,6 +886,8 @@
- if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
- pr_err("Warning: unable to open an initial console.\n");
-
-+ printk(KERN_WARNING "Starting Linux (built with OpenADK).\n");
-+
- (void) sys_dup(0);
- (void) sys_dup(0);
- /*
-@@ -894,7 +896,7 @@
- */
-
- if (!ramdisk_execute_command)
-- ramdisk_execute_command = "/init";
-+ ramdisk_execute_command = "/sbin/init";
-
- if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
- ramdisk_execute_command = NULL;
diff --git a/target/linux/patches/3.12.18/bsd-compatibility.patch b/target/linux/patches/3.12.18/bsd-compatibility.patch
deleted file mode 100644
index b954b658f..000000000
--- a/target/linux/patches/3.12.18/bsd-compatibility.patch
+++ /dev/null
@@ -1,2538 +0,0 @@
-diff -Nur linux-3.11.5.orig/scripts/Makefile.lib linux-3.11.5/scripts/Makefile.lib
---- linux-3.11.5.orig/scripts/Makefile.lib 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/scripts/Makefile.lib 2013-10-16 18:09:31.000000000 +0200
-@@ -281,7 +281,12 @@
- size_append = printf $(shell \
- dec_size=0; \
- for F in $1; do \
-- fsize=$$(stat -c "%s" $$F); \
-+ if stat -qs .>/dev/null 2>&1; then \
-+ statcmd='stat -f %z'; \
-+ else \
-+ statcmd='stat -c %s'; \
-+ fi; \
-+ fsize=$$($$statcmd $$F); \
- dec_size=$$(expr $$dec_size + $$fsize); \
- done; \
- printf "%08x\n" $$dec_size | \
-diff -Nur linux-3.11.5.orig/scripts/mod/mk_elfconfig.c linux-3.11.5/scripts/mod/mk_elfconfig.c
---- linux-3.11.5.orig/scripts/mod/mk_elfconfig.c 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/scripts/mod/mk_elfconfig.c 2013-10-16 18:09:31.000000000 +0200
-@@ -1,7 +1,18 @@
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
--#include <elf.h>
-+
-+#define EI_NIDENT (16)
-+#define ELFMAG "\177ELF"
-+
-+#define SELFMAG 4
-+#define EI_CLASS 4
-+#define ELFCLASS32 1 /* 32-bit objects */
-+#define ELFCLASS64 2 /* 64-bit objects */
-+
-+#define EI_DATA 5 /* Data encoding byte index */
-+#define ELFDATA2LSB 1 /* 2's complement, little endian */
-+#define ELFDATA2MSB 2 /* 2's complement, big endian */
-
- int
- main(int argc, char **argv)
-diff -Nur linux-3.11.5.orig/scripts/mod/modpost.h linux-3.11.5/scripts/mod/modpost.h
---- linux-3.11.5.orig/scripts/mod/modpost.h 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/scripts/mod/modpost.h 2013-10-16 18:09:31.000000000 +0200
-@@ -7,7 +7,2453 @@
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <unistd.h>
--#include <elf.h>
-+
-+
-+/* This file defines standard ELF types, structures, and macros.
-+ Copyright (C) 1995-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
-+ This file is part of the GNU C Library.
-+
-+ The GNU C Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Lesser General Public
-+ License as published by the Free Software Foundation; either
-+ version 2.1 of the License, or (at your option) any later version.
-+
-+ The GNU C Library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ Lesser General Public License for more details.
-+
-+ You should have received a copy of the GNU Lesser General Public
-+ License along with the GNU C Library; if not, write to the Free
-+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-+ 02111-1307 USA. */
-+
-+#ifndef _ELF_H
-+#define _ELF_H 1
-+
-+__BEGIN_DECLS
-+
-+/* Standard ELF types. */
-+
-+#include <stdint.h>
-+
-+/* Type for a 16-bit quantity. */
-+typedef uint16_t Elf32_Half;
-+typedef uint16_t Elf64_Half;
-+
-+/* Types for signed and unsigned 32-bit quantities. */
-+typedef uint32_t Elf32_Word;
-+typedef int32_t Elf32_Sword;
-+typedef uint32_t Elf64_Word;
-+typedef int32_t Elf64_Sword;
-+
-+/* Types for signed and unsigned 64-bit quantities. */
-+typedef uint64_t Elf32_Xword;
-+typedef int64_t Elf32_Sxword;
-+typedef uint64_t Elf64_Xword;
-+typedef int64_t Elf64_Sxword;
-+
-+/* Type of addresses. */
-+typedef uint32_t Elf32_Addr;
-+typedef uint64_t Elf64_Addr;
-+
-+/* Type of file offsets. */
-+typedef uint32_t Elf32_Off;
-+typedef uint64_t Elf64_Off;
-+
-+/* Type for section indices, which are 16-bit quantities. */
-+typedef uint16_t Elf32_Section;
-+typedef uint16_t Elf64_Section;
-+
-+/* Type for version symbol information. */
-+typedef Elf32_Half Elf32_Versym;
-+typedef Elf64_Half Elf64_Versym;
-+
-+
-+/* The ELF file header. This appears at the start of every ELF file. */
-+
-+#define EI_NIDENT (16)
-+
-+typedef struct
-+{
-+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
-+ Elf32_Half e_type; /* Object file type */
-+ Elf32_Half e_machine; /* Architecture */
-+ Elf32_Word e_version; /* Object file version */
-+ Elf32_Addr e_entry; /* Entry point virtual address */
-+ Elf32_Off e_phoff; /* Program header table file offset */
-+ Elf32_Off e_shoff; /* Section header table file offset */
-+ Elf32_Word e_flags; /* Processor-specific flags */
-+ Elf32_Half e_ehsize; /* ELF header size in bytes */
-+ Elf32_Half e_phentsize; /* Program header table entry size */
-+ Elf32_Half e_phnum; /* Program header table entry count */
-+ Elf32_Half e_shentsize; /* Section header table entry size */
-+ Elf32_Half e_shnum; /* Section header table entry count */
-+ Elf32_Half e_shstrndx; /* Section header string table index */
-+} Elf32_Ehdr;
-+
-+typedef struct
-+{
-+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
-+ Elf64_Half e_type; /* Object file type */
-+ Elf64_Half e_machine; /* Architecture */
-+ Elf64_Word e_version; /* Object file version */
-+ Elf64_Addr e_entry; /* Entry point virtual address */
-+ Elf64_Off e_phoff; /* Program header table file offset */
-+ Elf64_Off e_shoff; /* Section header table file offset */
-+ Elf64_Word e_flags; /* Processor-specific flags */
-+ Elf64_Half e_ehsize; /* ELF header size in bytes */
-+ Elf64_Half e_phentsize; /* Program header table entry size */
-+ Elf64_Half e_phnum; /* Program header table entry count */
-+ Elf64_Half e_shentsize; /* Section header table entry size */
-+ Elf64_Half e_shnum; /* Section header table entry count */
-+ Elf64_Half e_shstrndx; /* Section header string table index */
-+} Elf64_Ehdr;
-+
-+/* Fields in the e_ident array. The EI_* macros are indices into the
-+ array. The macros under each EI_* macro are the values the byte
-+ may have. */
-+
-+#define EI_MAG0 0 /* File identification byte 0 index */
-+#define ELFMAG0 0x7f /* Magic number byte 0 */
-+
-+#define EI_MAG1 1 /* File identification byte 1 index */
-+#define ELFMAG1 'E' /* Magic number byte 1 */
-+
-+#define EI_MAG2 2 /* File identification byte 2 index */
-+#define ELFMAG2 'L' /* Magic number byte 2 */
-+
-+#define EI_MAG3 3 /* File identification byte 3 index */
-+#define ELFMAG3 'F' /* Magic number byte 3 */
-+
-+/* Conglomeration of the identification bytes, for easy testing as a word. */
-+#define ELFMAG "\177ELF"
-+#define SELFMAG 4
-+
-+#define EI_CLASS 4 /* File class byte index */
-+#define ELFCLASSNONE 0 /* Invalid class */
-+#define ELFCLASS32 1 /* 32-bit objects */
-+#define ELFCLASS64 2 /* 64-bit objects */
-+#define ELFCLASSNUM 3
-+
-+#define EI_DATA 5 /* Data encoding byte index */
-+#define ELFDATANONE 0 /* Invalid data encoding */
-+#define ELFDATA2LSB 1 /* 2's complement, little endian */
-+#define ELFDATA2MSB 2 /* 2's complement, big endian */
-+#define ELFDATANUM 3
-+
-+#define EI_VERSION 6 /* File version byte index */
-+ /* Value must be EV_CURRENT */
-+
-+#define EI_OSABI 7 /* OS ABI identification */
-+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
-+#define ELFOSABI_SYSV 0 /* Alias. */
-+#define ELFOSABI_HPUX 1 /* HP-UX */
-+#define ELFOSABI_NETBSD 2 /* NetBSD. */
-+#define ELFOSABI_LINUX 3 /* Linux. */
-+#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
-+#define ELFOSABI_AIX 7 /* IBM AIX. */
-+#define ELFOSABI_IRIX 8 /* SGI Irix. */
-+#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
-+#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
-+#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
-+#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
-+#define ELFOSABI_ARM 97 /* ARM */
-+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
-+
-+#define EI_ABIVERSION 8 /* ABI version */
-+
-+#define EI_PAD 9 /* Byte index of padding bytes */
-+
-+/* Legal values for e_type (object file type). */
-+
-+#define ET_NONE 0 /* No file type */
-+#define ET_REL 1 /* Relocatable file */
-+#define ET_EXEC 2 /* Executable file */
-+#define ET_DYN 3 /* Shared object file */
-+#define ET_CORE 4 /* Core file */
-+#define ET_NUM 5 /* Number of defined types */
-+#define ET_LOOS 0xfe00 /* OS-specific range start */
-+#define ET_HIOS 0xfeff /* OS-specific range end */
-+#define ET_LOPROC 0xff00 /* Processor-specific range start */
-+#define ET_HIPROC 0xffff /* Processor-specific range end */
-+
-+/* Legal values for e_machine (architecture). */
-+
-+#define EM_NONE 0 /* No machine */
-+#define EM_M32 1 /* AT&T WE 32100 */
-+#define EM_SPARC 2 /* SUN SPARC */
-+#define EM_386 3 /* Intel 80386 */
-+#define EM_68K 4 /* Motorola m68k family */
-+#define EM_88K 5 /* Motorola m88k family */
-+#define EM_860 7 /* Intel 80860 */
-+#define EM_MIPS 8 /* MIPS R3000 big-endian */
-+#define EM_S370 9 /* IBM System/370 */
-+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
-+
-+#define EM_PARISC 15 /* HPPA */
-+#define EM_VPP500 17 /* Fujitsu VPP500 */
-+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
-+#define EM_960 19 /* Intel 80960 */
-+#define EM_PPC 20 /* PowerPC */
-+#define EM_PPC64 21 /* PowerPC 64-bit */
-+#define EM_S390 22 /* IBM S390 */
-+
-+#define EM_V800 36 /* NEC V800 series */
-+#define EM_FR20 37 /* Fujitsu FR20 */
-+#define EM_RH32 38 /* TRW RH-32 */
-+#define EM_RCE 39 /* Motorola RCE */
-+#define EM_ARM 40 /* ARM */
-+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
-+#define EM_SH 42 /* Hitachi SH */
-+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
-+#define EM_TRICORE 44 /* Siemens Tricore */
-+#define EM_ARC 45 /* Argonaut RISC Core */
-+#define EM_H8_300 46 /* Hitachi H8/300 */
-+#define EM_H8_300H 47 /* Hitachi H8/300H */
-+#define EM_H8S 48 /* Hitachi H8S */
-+#define EM_H8_500 49 /* Hitachi H8/500 */
-+#define EM_IA_64 50 /* Intel Merced */
-+#define EM_MIPS_X 51 /* Stanford MIPS-X */
-+#define EM_COLDFIRE 52 /* Motorola Coldfire */
-+#define EM_68HC12 53 /* Motorola M68HC12 */
-+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
-+#define EM_PCP 55 /* Siemens PCP */
-+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
-+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
-+#define EM_STARCORE 58 /* Motorola Start*Core processor */
-+#define EM_ME16 59 /* Toyota ME16 processor */
-+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
-+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
-+#define EM_X86_64 62 /* AMD x86-64 architecture */
-+#define EM_PDSP 63 /* Sony DSP Processor */
-+
-+#define EM_FX66 66 /* Siemens FX66 microcontroller */
-+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
-+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
-+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
-+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
-+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
-+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
-+#define EM_SVX 73 /* Silicon Graphics SVx */
-+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
-+#define EM_VAX 75 /* Digital VAX */
-+#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
-+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
-+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
-+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
-+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
-+#define EM_HUANY 81 /* Harvard University machine-independent object files */
-+#define EM_PRISM 82 /* SiTera Prism */
-+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
-+#define EM_FR30 84 /* Fujitsu FR30 */
-+#define EM_D10V 85 /* Mitsubishi D10V */
-+#define EM_D30V 86 /* Mitsubishi D30V */
-+#define EM_V850 87 /* NEC v850 */
-+#define EM_M32R 88 /* Mitsubishi M32R */
-+#define EM_MN10300 89 /* Matsushita MN10300 */
-+#define EM_MN10200 90 /* Matsushita MN10200 */
-+#define EM_PJ 91 /* picoJava */
-+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
-+#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
-+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
-+#define EM_NUM 95
-+
-+/* If it is necessary to assign new unofficial EM_* values, please
-+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
-+ chances of collision with official or non-GNU unofficial values. */
-+
-+#define EM_ALPHA 0x9026
-+
-+/* Legal values for e_version (version). */
-+
-+#define EV_NONE 0 /* Invalid ELF version */
-+#define EV_CURRENT 1 /* Current version */
-+#define EV_NUM 2
-+
-+/* Section header. */
-+
-+typedef struct
-+{
-+ Elf32_Word sh_name; /* Section name (string tbl index) */
-+ Elf32_Word sh_type; /* Section type */
-+ Elf32_Word sh_flags; /* Section flags */
-+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
-+ Elf32_Off sh_offset; /* Section file offset */
-+ Elf32_Word sh_size; /* Section size in bytes */
-+ Elf32_Word sh_link; /* Link to another section */
-+ Elf32_Word sh_info; /* Additional section information */
-+ Elf32_Word sh_addralign; /* Section alignment */
-+ Elf32_Word sh_entsize; /* Entry size if section holds table */
-+} Elf32_Shdr;
-+
-+typedef struct
-+{
-+ Elf64_Word sh_name; /* Section name (string tbl index) */
-+ Elf64_Word sh_type; /* Section type */
-+ Elf64_Xword sh_flags; /* Section flags */
-+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
-+ Elf64_Off sh_offset; /* Section file offset */
-+ Elf64_Xword sh_size; /* Section size in bytes */
-+ Elf64_Word sh_link; /* Link to another section */
-+ Elf64_Word sh_info; /* Additional section information */
-+ Elf64_Xword sh_addralign; /* Section alignment */
-+ Elf64_Xword sh_entsize; /* Entry size if section holds table */
-+} Elf64_Shdr;
-+
-+/* Special section indices. */
-+
-+#define SHN_UNDEF 0 /* Undefined section */
-+#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
-+#define SHN_LOPROC 0xff00 /* Start of processor-specific */
-+#define SHN_HIPROC 0xff1f /* End of processor-specific */
-+#define SHN_LOOS 0xff20 /* Start of OS-specific */
-+#define SHN_HIOS 0xff3f /* End of OS-specific */
-+#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
-+#define SHN_COMMON 0xfff2 /* Associated symbol is common */
-+#define SHN_XINDEX 0xffff /* Index is in extra table. */
-+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
-+
-+/* Legal values for sh_type (section type). */
-+
-+#define SHT_NULL 0 /* Section header table entry unused */
-+#define SHT_PROGBITS 1 /* Program data */
-+#define SHT_SYMTAB 2 /* Symbol table */
-+#define SHT_STRTAB 3 /* String table */
-+#define SHT_RELA 4 /* Relocation entries with addends */
-+#define SHT_HASH 5 /* Symbol hash table */
-+#define SHT_DYNAMIC 6 /* Dynamic linking information */
-+#define SHT_NOTE 7 /* Notes */
-+#define SHT_NOBITS 8 /* Program space with no data (bss) */
-+#define SHT_REL 9 /* Relocation entries, no addends */
-+#define SHT_SHLIB 10 /* Reserved */
-+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
-+#define SHT_INIT_ARRAY 14 /* Array of constructors */
-+#define SHT_FINI_ARRAY 15 /* Array of destructors */
-+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
-+#define SHT_GROUP 17 /* Section group */
-+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
-+#define SHT_NUM 19 /* Number of defined types. */
-+#define SHT_LOOS 0x60000000 /* Start OS-specific */
-+#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
-+#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
-+#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
-+#define SHT_SUNW_move 0x6ffffffa
-+#define SHT_SUNW_COMDAT 0x6ffffffb
-+#define SHT_SUNW_syminfo 0x6ffffffc
-+#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
-+#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
-+#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
-+#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
-+#define SHT_HIOS 0x6fffffff /* End OS-specific type */
-+#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
-+#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
-+#define SHT_LOUSER 0x80000000 /* Start of application-specific */
-+#define SHT_HIUSER 0x8fffffff /* End of application-specific */
-+
-+/* Legal values for sh_flags (section flags). */
-+
-+#define SHF_WRITE (1 << 0) /* Writable */
-+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
-+#define SHF_EXECINSTR (1 << 2) /* Executable */
-+#define SHF_MERGE (1 << 4) /* Might be merged */
-+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
-+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
-+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
-+#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling
-+ required */
-+#define SHF_GROUP (1 << 9) /* Section is member of a group. */
-+#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
-+#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
-+#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
-+
-+/* Section group handling. */
-+#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
-+
-+/* Symbol table entry. */
-+
-+typedef struct
-+{
-+ Elf32_Word st_name; /* Symbol name (string tbl index) */
-+ Elf32_Addr st_value; /* Symbol value */
-+ Elf32_Word st_size; /* Symbol size */
-+ unsigned char st_info; /* Symbol type and binding */
-+ unsigned char st_other; /* Symbol visibility */
-+ Elf32_Section st_shndx; /* Section index */
-+} Elf32_Sym;
-+
-+typedef struct
-+{
-+ Elf64_Word st_name; /* Symbol name (string tbl index) */
-+ unsigned char st_info; /* Symbol type and binding */
-+ unsigned char st_other; /* Symbol visibility */
-+ Elf64_Section st_shndx; /* Section index */
-+ Elf64_Addr st_value; /* Symbol value */
-+ Elf64_Xword st_size; /* Symbol size */
-+} Elf64_Sym;
-+
-+/* The syminfo section if available contains additional information about
-+ every dynamic symbol. */
-+
-+typedef struct
-+{
-+ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
-+ Elf32_Half si_flags; /* Per symbol flags */
-+} Elf32_Syminfo;
-+
-+typedef struct
-+{
-+ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
-+ Elf64_Half si_flags; /* Per symbol flags */
-+} Elf64_Syminfo;
-+
-+/* Possible values for si_boundto. */
-+#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
-+#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
-+#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
-+
-+/* Possible bitmasks for si_flags. */
-+#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
-+#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
-+#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
-+#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
-+ loaded */
-+/* Syminfo version values. */
-+#define SYMINFO_NONE 0
-+#define SYMINFO_CURRENT 1
-+#define SYMINFO_NUM 2
-+
-+
-+/* How to extract and insert information held in the st_info field. */
-+
-+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
-+#define ELF32_ST_TYPE(val) ((val) & 0xf)
-+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
-+
-+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
-+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
-+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
-+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
-+
-+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
-+
-+#define STB_LOCAL 0 /* Local symbol */
-+#define STB_GLOBAL 1 /* Global symbol */
-+#define STB_WEAK 2 /* Weak symbol */
-+#define STB_NUM 3 /* Number of defined types. */
-+#define STB_LOOS 10 /* Start of OS-specific */
-+#define STB_HIOS 12 /* End of OS-specific */
-+#define STB_LOPROC 13 /* Start of processor-specific */
-+#define STB_HIPROC 15 /* End of processor-specific */
-+
-+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
-+
-+#define STT_NOTYPE 0 /* Symbol type is unspecified */
-+#define STT_OBJECT 1 /* Symbol is a data object */
-+#define STT_FUNC 2 /* Symbol is a code object */
-+#define STT_SECTION 3 /* Symbol associated with a section */
-+#define STT_FILE 4 /* Symbol's name is file name */
-+#define STT_COMMON 5 /* Symbol is a common data object */
-+#define STT_TLS 6 /* Symbol is thread-local data object*/
-+#define STT_NUM 7 /* Number of defined types. */
-+#define STT_LOOS 10 /* Start of OS-specific */
-+#define STT_HIOS 12 /* End of OS-specific */
-+#define STT_LOPROC 13 /* Start of processor-specific */
-+#define STT_HIPROC 15 /* End of processor-specific */
-+
-+
-+/* Symbol table indices are found in the hash buckets and chain table
-+ of a symbol hash table section. This special index value indicates
-+ the end of a chain, meaning no further symbols are found in that bucket. */
-+
-+#define STN_UNDEF 0 /* End of a chain. */
-+
-+
-+/* How to extract and insert information held in the st_other field. */
-+
-+#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
-+
-+/* For ELF64 the definitions are the same. */
-+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
-+
-+/* Symbol visibility specification encoded in the st_other field. */
-+#define STV_DEFAULT 0 /* Default symbol visibility rules */
-+#define STV_INTERNAL 1 /* Processor specific hidden class */
-+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
-+#define STV_PROTECTED 3 /* Not preemptible, not exported */
-+
-+
-+/* Relocation table entry without addend (in section of type SHT_REL). */
-+
-+typedef struct
-+{
-+ Elf32_Addr r_offset; /* Address */
-+ Elf32_Word r_info; /* Relocation type and symbol index */
-+} Elf32_Rel;
-+
-+/* I have seen two different definitions of the Elf64_Rel and
-+ Elf64_Rela structures, so we'll leave them out until Novell (or
-+ whoever) gets their act together. */
-+/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
-+
-+typedef struct
-+{
-+ Elf64_Addr r_offset; /* Address */
-+ Elf64_Xword r_info; /* Relocation type and symbol index */
-+} Elf64_Rel;
-+
-+/* Relocation table entry with addend (in section of type SHT_RELA). */
-+
-+typedef struct
-+{
-+ Elf32_Addr r_offset; /* Address */
-+ Elf32_Word r_info; /* Relocation type and symbol index */
-+ Elf32_Sword r_addend; /* Addend */
-+} Elf32_Rela;
-+
-+typedef struct
-+{
-+ Elf64_Addr r_offset; /* Address */
-+ Elf64_Xword r_info; /* Relocation type and symbol index */
-+ Elf64_Sxword r_addend; /* Addend */
-+} Elf64_Rela;
-+
-+/* How to extract and insert information held in the r_info field. */
-+
-+#define ELF32_R_SYM(val) ((val) >> 8)
-+#define ELF32_R_TYPE(val) ((val) & 0xff)
-+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
-+
-+#define ELF64_R_SYM(i) ((i) >> 32)
-+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
-+#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
-+
-+/* Program segment header. */
-+
-+typedef struct
-+{
-+ Elf32_Word p_type; /* Segment type */
-+ Elf32_Off p_offset; /* Segment file offset */
-+ Elf32_Addr p_vaddr; /* Segment virtual address */
-+ Elf32_Addr p_paddr; /* Segment physical address */
-+ Elf32_Word p_filesz; /* Segment size in file */
-+ Elf32_Word p_memsz; /* Segment size in memory */
-+ Elf32_Word p_flags; /* Segment flags */
-+ Elf32_Word p_align; /* Segment alignment */
-+} Elf32_Phdr;
-+
-+typedef struct
-+{
-+ Elf64_Word p_type; /* Segment type */
-+ Elf64_Word p_flags; /* Segment flags */
-+ Elf64_Off p_offset; /* Segment file offset */
-+ Elf64_Addr p_vaddr; /* Segment virtual address */
-+ Elf64_Addr p_paddr; /* Segment physical address */
-+ Elf64_Xword p_filesz; /* Segment size in file */
-+ Elf64_Xword p_memsz; /* Segment size in memory */
-+ Elf64_Xword p_align; /* Segment alignment */
-+} Elf64_Phdr;
-+
-+/* Legal values for p_type (segment type). */
-+
-+#define PT_NULL 0 /* Program header table entry unused */
-+#define PT_LOAD 1 /* Loadable program segment */
-+#define PT_DYNAMIC 2 /* Dynamic linking information */
-+#define PT_INTERP 3 /* Program interpreter */
-+#define PT_NOTE 4 /* Auxiliary information */
-+#define PT_SHLIB 5 /* Reserved */
-+#define PT_PHDR 6 /* Entry for header table itself */
-+#define PT_TLS 7 /* Thread-local storage segment */
-+#define PT_NUM 8 /* Number of defined types */
-+#define PT_LOOS 0x60000000 /* Start of OS-specific */
-+#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
-+#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
-+#define PT_LOSUNW 0x6ffffffa
-+#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
-+#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
-+#define PT_HISUNW 0x6fffffff
-+#define PT_HIOS 0x6fffffff /* End of OS-specific */
-+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
-+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
-+
-+/* Legal values for p_flags (segment flags). */
-+
-+#define PF_X (1 << 0) /* Segment is executable */
-+#define PF_W (1 << 1) /* Segment is writable */
-+#define PF_R (1 << 2) /* Segment is readable */
-+#define PF_MASKOS 0x0ff00000 /* OS-specific */
-+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
-+
-+/* Legal values for note segment descriptor types for core files. */
-+
-+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
-+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
-+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
-+#define NT_PRXREG 4 /* Contains copy of prxregset struct */
-+#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
-+#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
-+#define NT_AUXV 6 /* Contains copy of auxv array */
-+#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
-+#define NT_ASRS 8 /* Contains copy of asrset struct */
-+#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
-+#define NT_PSINFO 13 /* Contains copy of psinfo struct */
-+#define NT_PRCRED 14 /* Contains copy of prcred struct */
-+#define NT_UTSNAME 15 /* Contains copy of utsname struct */
-+#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
-+#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
-+#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/
-+
-+/* Legal values for the note segment descriptor types for object files. */
-+
-+#define NT_VERSION 1 /* Contains a version string. */
-+
-+
-+/* Dynamic section entry. */
-+
-+typedef struct
-+{
-+ Elf32_Sword d_tag; /* Dynamic entry type */
-+ union
-+ {
-+ Elf32_Word d_val; /* Integer value */
-+ Elf32_Addr d_ptr; /* Address value */
-+ } d_un;
-+} Elf32_Dyn;
-+
-+typedef struct
-+{
-+ Elf64_Sxword d_tag; /* Dynamic entry type */
-+ union
-+ {
-+ Elf64_Xword d_val; /* Integer value */
-+ Elf64_Addr d_ptr; /* Address value */
-+ } d_un;
-+} Elf64_Dyn;
-+
-+/* Legal values for d_tag (dynamic entry type). */
-+
-+#define DT_NULL 0 /* Marks end of dynamic section */
-+#define DT_NEEDED 1 /* Name of needed library */
-+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
-+#define DT_PLTGOT 3 /* Processor defined value */
-+#define DT_HASH 4 /* Address of symbol hash table */
-+#define DT_STRTAB 5 /* Address of string table */
-+#define DT_SYMTAB 6 /* Address of symbol table */
-+#define DT_RELA 7 /* Address of Rela relocs */
-+#define DT_RELASZ 8 /* Total size of Rela relocs */
-+#define DT_RELAENT 9 /* Size of one Rela reloc */
-+#define DT_STRSZ 10 /* Size of string table */
-+#define DT_SYMENT 11 /* Size of one symbol table entry */
-+#define DT_INIT 12 /* Address of init function */
-+#define DT_FINI 13 /* Address of termination function */
-+#define DT_SONAME 14 /* Name of shared object */
-+#define DT_RPATH 15 /* Library search path (deprecated) */
-+#define DT_SYMBOLIC 16 /* Start symbol search here */
-+#define DT_REL 17 /* Address of Rel relocs */
-+#define DT_RELSZ 18 /* Total size of Rel relocs */
-+#define DT_RELENT 19 /* Size of one Rel reloc */
-+#define DT_PLTREL 20 /* Type of reloc in PLT */
-+#define DT_DEBUG 21 /* For debugging; unspecified */
-+#define DT_TEXTREL 22 /* Reloc might modify .text */
-+#define DT_JMPREL 23 /* Address of PLT relocs */
-+#define DT_BIND_NOW 24 /* Process relocations of object */
-+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
-+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
-+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
-+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
-+#define DT_RUNPATH 29 /* Library search path */
-+#define DT_FLAGS 30 /* Flags for the object being loaded */
-+#define DT_ENCODING 32 /* Start of encoded range */
-+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
-+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
-+#define DT_NUM 34 /* Number used */
-+#define DT_LOOS 0x6000000d /* Start of OS-specific */
-+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
-+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
-+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
-+#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
-+
-+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
-+ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
-+ approach. */
-+#define DT_VALRNGLO 0x6ffffd00
-+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
-+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
-+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
-+#define DT_CHECKSUM 0x6ffffdf8
-+#define DT_PLTPADSZ 0x6ffffdf9
-+#define DT_MOVEENT 0x6ffffdfa
-+#define DT_MOVESZ 0x6ffffdfb
-+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
-+#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
-+ the following DT_* entry. */
-+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
-+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
-+#define DT_VALRNGHI 0x6ffffdff
-+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
-+#define DT_VALNUM 12
-+
-+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
-+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
-+
-+ If any adjustment is made to the ELF object after it has been
-+ built these entries will need to be adjusted. */
-+#define DT_ADDRRNGLO 0x6ffffe00
-+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
-+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
-+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
-+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
-+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
-+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
-+#define DT_MOVETAB 0x6ffffefe /* Move table. */
-+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
-+#define DT_ADDRRNGHI 0x6ffffeff
-+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
-+#define DT_ADDRNUM 10
-+
-+/* The versioning entry types. The next are defined as part of the
-+ GNU extension. */
-+#define DT_VERSYM 0x6ffffff0
-+
-+#define DT_RELACOUNT 0x6ffffff9
-+#define DT_RELCOUNT 0x6ffffffa
-+
-+/* These were chosen by Sun. */
-+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
-+#define DT_VERDEF 0x6ffffffc /* Address of version definition
-+ table */
-+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
-+#define DT_VERNEED 0x6ffffffe /* Address of table with needed
-+ versions */
-+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
-+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
-+#define DT_VERSIONTAGNUM 16
-+
-+/* Sun added these machine-independent extensions in the "processor-specific"
-+ range. Be compatible. */
-+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
-+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
-+#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
-+#define DT_EXTRANUM 3
-+
-+/* Values of `d_un.d_val' in the DT_FLAGS entry. */
-+#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
-+#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
-+#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
-+#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
-+#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
-+
-+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
-+ entry in the dynamic section. */
-+#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
-+#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
-+#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
-+#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
-+#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
-+#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
-+#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
-+#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
-+#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
-+#define DF_1_TRANS 0x00000200
-+#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
-+#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
-+#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
-+#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
-+#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
-+#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
-+#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
-+
-+/* Flags for the feature selection in DT_FEATURE_1. */
-+#define DTF_1_PARINIT 0x00000001
-+#define DTF_1_CONFEXP 0x00000002
-+
-+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
-+#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
-+#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not
-+ generally available. */
-+
-+/* Version definition sections. */
-+
-+typedef struct
-+{
-+ Elf32_Half vd_version; /* Version revision */
-+ Elf32_Half vd_flags; /* Version information */
-+ Elf32_Half vd_ndx; /* Version Index */
-+ Elf32_Half vd_cnt; /* Number of associated aux entries */
-+ Elf32_Word vd_hash; /* Version name hash value */
-+ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
-+ Elf32_Word vd_next; /* Offset in bytes to next verdef
-+ entry */
-+} Elf32_Verdef;
-+
-+typedef struct
-+{
-+ Elf64_Half vd_version; /* Version revision */
-+ Elf64_Half vd_flags; /* Version information */
-+ Elf64_Half vd_ndx; /* Version Index */
-+ Elf64_Half vd_cnt; /* Number of associated aux entries */
-+ Elf64_Word vd_hash; /* Version name hash value */
-+ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
-+ Elf64_Word vd_next; /* Offset in bytes to next verdef
-+ entry */
-+} Elf64_Verdef;
-+
-+
-+/* Legal values for vd_version (version revision). */
-+#define VER_DEF_NONE 0 /* No version */
-+#define VER_DEF_CURRENT 1 /* Current version */
-+#define VER_DEF_NUM 2 /* Given version number */
-+
-+/* Legal values for vd_flags (version information flags). */
-+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
-+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
-+
-+/* Versym symbol index values. */
-+#define VER_NDX_LOCAL 0 /* Symbol is local. */
-+#define VER_NDX_GLOBAL 1 /* Symbol is global. */
-+#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
-+#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
-+
-+/* Auxialiary version information. */
-+
-+typedef struct
-+{
-+ Elf32_Word vda_name; /* Version or dependency names */
-+ Elf32_Word vda_next; /* Offset in bytes to next verdaux
-+ entry */
-+} Elf32_Verdaux;
-+
-+typedef struct
-+{
-+ Elf64_Word vda_name; /* Version or dependency names */
-+ Elf64_Word vda_next; /* Offset in bytes to next verdaux
-+ entry */
-+} Elf64_Verdaux;
-+
-+
-+/* Version dependency section. */
-+
-+typedef struct
-+{
-+ Elf32_Half vn_version; /* Version of structure */
-+ Elf32_Half vn_cnt; /* Number of associated aux entries */
-+ Elf32_Word vn_file; /* Offset of filename for this
-+ dependency */
-+ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
-+ Elf32_Word vn_next; /* Offset in bytes to next verneed
-+ entry */
-+} Elf32_Verneed;
-+
-+typedef struct
-+{
-+ Elf64_Half vn_version; /* Version of structure */
-+ Elf64_Half vn_cnt; /* Number of associated aux entries */
-+ Elf64_Word vn_file; /* Offset of filename for this
-+ dependency */
-+ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
-+ Elf64_Word vn_next; /* Offset in bytes to next verneed
-+ entry */
-+} Elf64_Verneed;
-+
-+
-+/* Legal values for vn_version (version revision). */
-+#define VER_NEED_NONE 0 /* No version */
-+#define VER_NEED_CURRENT 1 /* Current version */
-+#define VER_NEED_NUM 2 /* Given version number */
-+
-+/* Auxiliary needed version information. */
-+
-+typedef struct
-+{
-+ Elf32_Word vna_hash; /* Hash value of dependency name */
-+ Elf32_Half vna_flags; /* Dependency specific information */
-+ Elf32_Half vna_other; /* Unused */
-+ Elf32_Word vna_name; /* Dependency name string offset */
-+ Elf32_Word vna_next; /* Offset in bytes to next vernaux
-+ entry */
-+} Elf32_Vernaux;
-+
-+typedef struct
-+{
-+ Elf64_Word vna_hash; /* Hash value of dependency name */
-+ Elf64_Half vna_flags; /* Dependency specific information */
-+ Elf64_Half vna_other; /* Unused */
-+ Elf64_Word vna_name; /* Dependency name string offset */
-+ Elf64_Word vna_next; /* Offset in bytes to next vernaux
-+ entry */
-+} Elf64_Vernaux;
-+
-+
-+/* Legal values for vna_flags. */
-+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
-+
-+
-+/* Auxiliary vector. */
-+
-+/* This vector is normally only used by the program interpreter. The
-+ usual definition in an ABI supplement uses the name auxv_t. The
-+ vector is not usually defined in a standard <elf.h> file, but it
-+ can't hurt. We rename it to avoid conflicts. The sizes of these
-+ types are an arrangement between the exec server and the program
-+ interpreter, so we don't fully specify them here. */
-+
-+typedef struct
-+{
-+ int a_type; /* Entry type */
-+ union
-+ {
-+ long int a_val; /* Integer value */
-+ void *a_ptr; /* Pointer value */
-+ void (*a_fcn) (void); /* Function pointer value */
-+ } a_un;
-+} Elf32_auxv_t;
-+
-+typedef struct
-+{
-+ long int a_type; /* Entry type */
-+ union
-+ {
-+ long int a_val; /* Integer value */
-+ void *a_ptr; /* Pointer value */
-+ void (*a_fcn) (void); /* Function pointer value */
-+ } a_un;
-+} Elf64_auxv_t;
-+
-+/* Legal values for a_type (entry type). */
-+
-+#define AT_NULL 0 /* End of vector */
-+#define AT_IGNORE 1 /* Entry should be ignored */
-+#define AT_EXECFD 2 /* File descriptor of program */
-+#define AT_PHDR 3 /* Program headers for program */
-+#define AT_PHENT 4 /* Size of program header entry */
-+#define AT_PHNUM 5 /* Number of program headers */
-+#define AT_PAGESZ 6 /* System page size */
-+#define AT_BASE 7 /* Base address of interpreter */
-+#define AT_FLAGS 8 /* Flags */
-+#define AT_ENTRY 9 /* Entry point of program */
-+#define AT_NOTELF 10 /* Program is not ELF */
-+#define AT_UID 11 /* Real uid */
-+#define AT_EUID 12 /* Effective uid */
-+#define AT_GID 13 /* Real gid */
-+#define AT_EGID 14 /* Effective gid */
-+#define AT_CLKTCK 17 /* Frequency of times() */
-+
-+/* Some more special a_type values describing the hardware. */
-+#define AT_PLATFORM 15 /* String identifying platform. */
-+#define AT_HWCAP 16 /* Machine dependent hints about
-+ processor capabilities. */
-+
-+/* This entry gives some information about the FPU initialization
-+ performed by the kernel. */
-+#define AT_FPUCW 18 /* Used FPU control word. */
-+
-+/* Cache block sizes. */
-+#define AT_DCACHEBSIZE 19 /* Data cache block size. */
-+#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */
-+#define AT_UCACHEBSIZE 21 /* Unified cache block size. */
-+
-+/* A special ignored value for PPC, used by the kernel to control the
-+ interpretation of the AUXV. Must be > 16. */
-+#define AT_IGNOREPPC 22 /* Entry should be ignored. */
-+
-+#define AT_SECURE 23 /* Boolean, was exec setuid-like? */
-+
-+/* Pointer to the global system page used for system calls and other
-+ nice things. */
-+#define AT_SYSINFO 32
-+#define AT_SYSINFO_EHDR 33
-+
-+
-+/* Note section contents. Each entry in the note section begins with
-+ a header of a fixed form. */
-+
-+typedef struct
-+{
-+ Elf32_Word n_namesz; /* Length of the note's name. */
-+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
-+ Elf32_Word n_type; /* Type of the note. */
-+} Elf32_Nhdr;
-+
-+typedef struct
-+{
-+ Elf64_Word n_namesz; /* Length of the note's name. */
-+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
-+ Elf64_Word n_type; /* Type of the note. */
-+} Elf64_Nhdr;
-+
-+/* Known names of notes. */
-+
-+/* Solaris entries in the note section have this name. */
-+#define ELF_NOTE_SOLARIS "SUNW Solaris"
-+
-+/* Note entries for GNU systems have this name. */
-+#define ELF_NOTE_GNU "GNU"
-+
-+
-+/* Defined types of notes for Solaris. */
-+
-+/* Value of descriptor (one word) is desired pagesize for the binary. */
-+#define ELF_NOTE_PAGESIZE_HINT 1
-+
-+
-+/* Defined note types for GNU systems. */
-+
-+/* ABI information. The descriptor consists of words:
-+ word 0: OS descriptor
-+ word 1: major version of the ABI
-+ word 2: minor version of the ABI
-+ word 3: subminor version of the ABI
-+*/
-+#define ELF_NOTE_ABI 1
-+
-+/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI
-+ note section entry. */
-+#define ELF_NOTE_OS_LINUX 0
-+#define ELF_NOTE_OS_GNU 1
-+#define ELF_NOTE_OS_SOLARIS2 2
-+#define ELF_NOTE_OS_FREEBSD 3
-+
-+
-+/* Move records. */
-+typedef struct
-+{
-+ Elf32_Xword m_value; /* Symbol value. */
-+ Elf32_Word m_info; /* Size and index. */
-+ Elf32_Word m_poffset; /* Symbol offset. */
-+ Elf32_Half m_repeat; /* Repeat count. */
-+ Elf32_Half m_stride; /* Stride info. */
-+} Elf32_Move;
-+
-+typedef struct
-+{
-+ Elf64_Xword m_value; /* Symbol value. */
-+ Elf64_Xword m_info; /* Size and index. */
-+ Elf64_Xword m_poffset; /* Symbol offset. */
-+ Elf64_Half m_repeat; /* Repeat count. */
-+ Elf64_Half m_stride; /* Stride info. */
-+} Elf64_Move;
-+
-+/* Macro to construct move records. */
-+#define ELF32_M_SYM(info) ((info) >> 8)
-+#define ELF32_M_SIZE(info) ((unsigned char) (info))
-+#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size))
-+
-+#define ELF64_M_SYM(info) ELF32_M_SYM (info)
-+#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
-+#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
-+
-+
-+/* Motorola 68k specific definitions. */
-+
-+/* Values for Elf32_Ehdr.e_flags. */
-+#define EF_CPU32 0x00810000
-+
-+/* m68k relocs. */
-+
-+#define R_68K_NONE 0 /* No reloc */
-+#define R_68K_32 1 /* Direct 32 bit */
-+#define R_68K_16 2 /* Direct 16 bit */
-+#define R_68K_8 3 /* Direct 8 bit */
-+#define R_68K_PC32 4 /* PC relative 32 bit */
-+#define R_68K_PC16 5 /* PC relative 16 bit */
-+#define R_68K_PC8 6 /* PC relative 8 bit */
-+#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
-+#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
-+#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
-+#define R_68K_GOT32O 10 /* 32 bit GOT offset */
-+#define R_68K_GOT16O 11 /* 16 bit GOT offset */
-+#define R_68K_GOT8O 12 /* 8 bit GOT offset */
-+#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
-+#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
-+#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
-+#define R_68K_PLT32O 16 /* 32 bit PLT offset */
-+#define R_68K_PLT16O 17 /* 16 bit PLT offset */
-+#define R_68K_PLT8O 18 /* 8 bit PLT offset */
-+#define R_68K_COPY 19 /* Copy symbol at runtime */
-+#define R_68K_GLOB_DAT 20 /* Create GOT entry */
-+#define R_68K_JMP_SLOT 21 /* Create PLT entry */
-+#define R_68K_RELATIVE 22 /* Adjust by program base */
-+/* Keep this the last entry. */
-+#define R_68K_NUM 23
-+
-+/* Intel 80386 specific definitions. */
-+
-+/* i386 relocs. */
-+
-+#define R_386_NONE 0 /* No reloc */
-+#define R_386_32 1 /* Direct 32 bit */
-+#define R_386_PC32 2 /* PC relative 32 bit */
-+#define R_386_GOT32 3 /* 32 bit GOT entry */
-+#define R_386_PLT32 4 /* 32 bit PLT address */
-+#define R_386_COPY 5 /* Copy symbol at runtime */
-+#define R_386_GLOB_DAT 6 /* Create GOT entry */
-+#define R_386_JMP_SLOT 7 /* Create PLT entry */
-+#define R_386_RELATIVE 8 /* Adjust by program base */
-+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
-+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
-+#define R_386_32PLT 11
-+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
-+#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
-+ block offset */
-+#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
-+ offset */
-+#define R_386_TLS_LE 17 /* Offset relative to static TLS
-+ block */
-+#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
-+ general dynamic thread local data */
-+#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
-+ local dynamic thread local data
-+ in LE code */
-+#define R_386_16 20
-+#define R_386_PC16 21
-+#define R_386_8 22
-+#define R_386_PC8 23
-+#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
-+ thread local data */
-+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
-+#define R_386_TLS_GD_CALL 26 /* Relocation for call to
-+ __tls_get_addr() */
-+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
-+#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
-+ thread local data in LE code */
-+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
-+#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
-+ __tls_get_addr() in LDM code */
-+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
-+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
-+#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
-+ block offset */
-+#define R_386_TLS_LE_32 34 /* Negated offset relative to static
-+ TLS block */
-+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
-+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
-+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
-+/* Keep this the last entry. */
-+#define R_386_NUM 38
-+
-+/* SUN SPARC specific definitions. */
-+
-+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
-+
-+#define STT_REGISTER 13 /* Global register reserved to app. */
-+
-+/* Values for Elf64_Ehdr.e_flags. */
-+
-+#define EF_SPARCV9_MM 3
-+#define EF_SPARCV9_TSO 0
-+#define EF_SPARCV9_PSO 1
-+#define EF_SPARCV9_RMO 2
-+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
-+#define EF_SPARC_EXT_MASK 0xFFFF00
-+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
-+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
-+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
-+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
-+
-+/* SPARC relocs. */
-+
-+#define R_SPARC_NONE 0 /* No reloc */
-+#define R_SPARC_8 1 /* Direct 8 bit */
-+#define R_SPARC_16 2 /* Direct 16 bit */
-+#define R_SPARC_32 3 /* Direct 32 bit */
-+#define R_SPARC_DISP8 4 /* PC relative 8 bit */
-+#define R_SPARC_DISP16 5 /* PC relative 16 bit */
-+#define R_SPARC_DISP32 6 /* PC relative 32 bit */
-+#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
-+#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
-+#define R_SPARC_HI22 9 /* High 22 bit */
-+#define R_SPARC_22 10 /* Direct 22 bit */
-+#define R_SPARC_13 11 /* Direct 13 bit */
-+#define R_SPARC_LO10 12 /* Truncated 10 bit */
-+#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
-+#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
-+#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
-+#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
-+#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
-+#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
-+#define R_SPARC_COPY 19 /* Copy symbol at runtime */
-+#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
-+#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
-+#define R_SPARC_RELATIVE 22 /* Adjust by program base */
-+#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
-+
-+/* Additional Sparc64 relocs. */
-+
-+#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
-+#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
-+#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
-+#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
-+#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
-+#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
-+#define R_SPARC_10 30 /* Direct 10 bit */
-+#define R_SPARC_11 31 /* Direct 11 bit */
-+#define R_SPARC_64 32 /* Direct 64 bit */
-+#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
-+#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
-+#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
-+#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
-+#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
-+#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
-+#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
-+#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
-+#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
-+#define R_SPARC_7 43 /* Direct 7 bit */
-+#define R_SPARC_5 44 /* Direct 5 bit */
-+#define R_SPARC_6 45 /* Direct 6 bit */
-+#define R_SPARC_DISP64 46 /* PC relative 64 bit */
-+#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
-+#define R_SPARC_HIX22 48 /* High 22 bit complemented */
-+#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
-+#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
-+#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
-+#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
-+#define R_SPARC_REGISTER 53 /* Global register usage */
-+#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
-+#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
-+#define R_SPARC_TLS_GD_HI22 56
-+#define R_SPARC_TLS_GD_LO10 57
-+#define R_SPARC_TLS_GD_ADD 58
-+#define R_SPARC_TLS_GD_CALL 59
-+#define R_SPARC_TLS_LDM_HI22 60
-+#define R_SPARC_TLS_LDM_LO10 61
-+#define R_SPARC_TLS_LDM_ADD 62
-+#define R_SPARC_TLS_LDM_CALL 63
-+#define R_SPARC_TLS_LDO_HIX22 64
-+#define R_SPARC_TLS_LDO_LOX10 65
-+#define R_SPARC_TLS_LDO_ADD 66
-+#define R_SPARC_TLS_IE_HI22 67
-+#define R_SPARC_TLS_IE_LO10 68
-+#define R_SPARC_TLS_IE_LD 69
-+#define R_SPARC_TLS_IE_LDX 70
-+#define R_SPARC_TLS_IE_ADD 71
-+#define R_SPARC_TLS_LE_HIX22 72
-+#define R_SPARC_TLS_LE_LOX10 73
-+#define R_SPARC_TLS_DTPMOD32 74
-+#define R_SPARC_TLS_DTPMOD64 75
-+#define R_SPARC_TLS_DTPOFF32 76
-+#define R_SPARC_TLS_DTPOFF64 77
-+#define R_SPARC_TLS_TPOFF32 78
-+#define R_SPARC_TLS_TPOFF64 79
-+/* Keep this the last entry. */
-+#define R_SPARC_NUM 80
-+
-+/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
-+
-+#define DT_SPARC_REGISTER 0x70000001
-+#define DT_SPARC_NUM 2
-+
-+/* Bits present in AT_HWCAP, primarily for Sparc32. */
-+
-+#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */
-+#define HWCAP_SPARC_STBAR 2
-+#define HWCAP_SPARC_SWAP 4
-+#define HWCAP_SPARC_MULDIV 8
-+#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */
-+#define HWCAP_SPARC_ULTRA3 32
-+
-+/* MIPS R3000 specific definitions. */
-+
-+/* Legal values for e_flags field of Elf32_Ehdr. */
-+
-+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */
-+#define EF_MIPS_PIC 2 /* Contains PIC code */
-+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */
-+#define EF_MIPS_XGOT 8
-+#define EF_MIPS_64BIT_WHIRL 16
-+#define EF_MIPS_ABI2 32
-+#define EF_MIPS_ABI_ON32 64
-+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */
-+
-+/* Legal values for MIPS architecture level. */
-+
-+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
-+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
-+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
-+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
-+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
-+#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
-+#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
-+
-+/* The following are non-official names and should not be used. */
-+
-+#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
-+#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
-+#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
-+#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
-+#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
-+#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
-+#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
-+
-+/* Special section indices. */
-+
-+#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */
-+#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
-+#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
-+#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */
-+#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */
-+
-+/* Legal values for sh_type field of Elf32_Shdr. */
-+
-+#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */
-+#define SHT_MIPS_MSYM 0x70000001
-+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */
-+#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */
-+#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
-+#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/
-+#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */
-+#define SHT_MIPS_PACKAGE 0x70000007
-+#define SHT_MIPS_PACKSYM 0x70000008
-+#define SHT_MIPS_RELD 0x70000009
-+#define SHT_MIPS_IFACE 0x7000000b
-+#define SHT_MIPS_CONTENT 0x7000000c
-+#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
-+#define SHT_MIPS_SHDR 0x70000010
-+#define SHT_MIPS_FDESC 0x70000011
-+#define SHT_MIPS_EXTSYM 0x70000012
-+#define SHT_MIPS_DENSE 0x70000013
-+#define SHT_MIPS_PDESC 0x70000014
-+#define SHT_MIPS_LOCSYM 0x70000015
-+#define SHT_MIPS_AUXSYM 0x70000016
-+#define SHT_MIPS_OPTSYM 0x70000017
-+#define SHT_MIPS_LOCSTR 0x70000018
-+#define SHT_MIPS_LINE 0x70000019
-+#define SHT_MIPS_RFDESC 0x7000001a
-+#define SHT_MIPS_DELTASYM 0x7000001b
-+#define SHT_MIPS_DELTAINST 0x7000001c
-+#define SHT_MIPS_DELTACLASS 0x7000001d
-+#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
-+#define SHT_MIPS_DELTADECL 0x7000001f
-+#define SHT_MIPS_SYMBOL_LIB 0x70000020
-+#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
-+#define SHT_MIPS_TRANSLATE 0x70000022
-+#define SHT_MIPS_PIXIE 0x70000023
-+#define SHT_MIPS_XLATE 0x70000024
-+#define SHT_MIPS_XLATE_DEBUG 0x70000025
-+#define SHT_MIPS_WHIRL 0x70000026
-+#define SHT_MIPS_EH_REGION 0x70000027
-+#define SHT_MIPS_XLATE_OLD 0x70000028
-+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
-+
-+/* Legal values for sh_flags field of Elf32_Shdr. */
-+
-+#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */
-+#define SHF_MIPS_MERGE 0x20000000
-+#define SHF_MIPS_ADDR 0x40000000
-+#define SHF_MIPS_STRINGS 0x80000000
-+#define SHF_MIPS_NOSTRIP 0x08000000
-+#define SHF_MIPS_LOCAL 0x04000000
-+#define SHF_MIPS_NAMES 0x02000000
-+#define SHF_MIPS_NODUPE 0x01000000
-+
-+
-+/* Symbol tables. */
-+
-+/* MIPS specific values for `st_other'. */
-+#define STO_MIPS_DEFAULT 0x0
-+#define STO_MIPS_INTERNAL 0x1
-+#define STO_MIPS_HIDDEN 0x2
-+#define STO_MIPS_PROTECTED 0x3
-+#define STO_MIPS_SC_ALIGN_UNUSED 0xff
-+
-+/* MIPS specific values for `st_info'. */
-+#define STB_MIPS_SPLIT_COMMON 13
-+
-+/* Entries found in sections of type SHT_MIPS_GPTAB. */
-+
-+typedef union
-+{
-+ struct
-+ {
-+ Elf32_Word gt_current_g_value; /* -G value used for compilation */
-+ Elf32_Word gt_unused; /* Not used */
-+ } gt_header; /* First entry in section */
-+ struct
-+ {
-+ Elf32_Word gt_g_value; /* If this value were used for -G */
-+ Elf32_Word gt_bytes; /* This many bytes would be used */
-+ } gt_entry; /* Subsequent entries in section */
-+} Elf32_gptab;
-+
-+/* Entry found in sections of type SHT_MIPS_REGINFO. */
-+
-+typedef struct
-+{
-+ Elf32_Word ri_gprmask; /* General registers used */
-+ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */
-+ Elf32_Sword ri_gp_value; /* $gp register value */
-+} Elf32_RegInfo;
-+
-+/* Entries found in sections of type SHT_MIPS_OPTIONS. */
-+
-+typedef struct
-+{
-+ unsigned char kind; /* Determines interpretation of the
-+ variable part of descriptor. */
-+ unsigned char size; /* Size of descriptor, including header. */
-+ Elf32_Section section; /* Section header index of section affected,
-+ 0 for global options. */
-+ Elf32_Word info; /* Kind-specific information. */
-+} Elf_Options;
-+
-+/* Values for `kind' field in Elf_Options. */
-+
-+#define ODK_NULL 0 /* Undefined. */
-+#define ODK_REGINFO 1 /* Register usage information. */
-+#define ODK_EXCEPTIONS 2 /* Exception processing options. */
-+#define ODK_PAD 3 /* Section padding options. */
-+#define ODK_HWPATCH 4 /* Hardware workarounds performed */
-+#define ODK_FILL 5 /* record the fill value used by the linker. */
-+#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
-+#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
-+#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
-+
-+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
-+
-+#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
-+#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
-+#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
-+#define OEX_SMM 0x20000 /* Force sequential memory mode? */
-+#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
-+#define OEX_PRECISEFP OEX_FPDBUG
-+#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
-+
-+#define OEX_FPU_INVAL 0x10
-+#define OEX_FPU_DIV0 0x08
-+#define OEX_FPU_OFLO 0x04
-+#define OEX_FPU_UFLO 0x02
-+#define OEX_FPU_INEX 0x01
-+
-+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
-+
-+#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
-+#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
-+#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
-+#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
-+
-+#define OPAD_PREFIX 0x1
-+#define OPAD_POSTFIX 0x2
-+#define OPAD_SYMBOL 0x4
-+
-+/* Entry found in `.options' section. */
-+
-+typedef struct
-+{
-+ Elf32_Word hwp_flags1; /* Extra flags. */
-+ Elf32_Word hwp_flags2; /* Extra flags. */
-+} Elf_Options_Hw;
-+
-+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
-+
-+#define OHWA0_R4KEOP_CHECKED 0x00000001
-+#define OHWA1_R4KEOP_CLEAN 0x00000002
-+
-+/* MIPS relocs. */
-+
-+#define R_MIPS_NONE 0 /* No reloc */
-+#define R_MIPS_16 1 /* Direct 16 bit */
-+#define R_MIPS_32 2 /* Direct 32 bit */
-+#define R_MIPS_REL32 3 /* PC relative 32 bit */
-+#define R_MIPS_26 4 /* Direct 26 bit shifted */
-+#define R_MIPS_HI16 5 /* High 16 bit */
-+#define R_MIPS_LO16 6 /* Low 16 bit */
-+#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
-+#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
-+#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
-+#define R_MIPS_PC16 10 /* PC relative 16 bit */
-+#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
-+#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
-+
-+#define R_MIPS_SHIFT5 16
-+#define R_MIPS_SHIFT6 17
-+#define R_MIPS_64 18
-+#define R_MIPS_GOT_DISP 19
-+#define R_MIPS_GOT_PAGE 20
-+#define R_MIPS_GOT_OFST 21
-+#define R_MIPS_GOT_HI16 22
-+#define R_MIPS_GOT_LO16 23
-+#define R_MIPS_SUB 24
-+#define R_MIPS_INSERT_A 25
-+#define R_MIPS_INSERT_B 26
-+#define R_MIPS_DELETE 27
-+#define R_MIPS_HIGHER 28
-+#define R_MIPS_HIGHEST 29
-+#define R_MIPS_CALL_HI16 30
-+#define R_MIPS_CALL_LO16 31
-+#define R_MIPS_SCN_DISP 32
-+#define R_MIPS_REL16 33
-+#define R_MIPS_ADD_IMMEDIATE 34
-+#define R_MIPS_PJUMP 35
-+#define R_MIPS_RELGOT 36
-+#define R_MIPS_JALR 37
-+/* Keep this the last entry. */
-+#define R_MIPS_NUM 38
-+
-+/* Legal values for p_type field of Elf32_Phdr. */
-+
-+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
-+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
-+#define PT_MIPS_OPTIONS 0x70000002
-+
-+/* Special program header types. */
-+
-+#define PF_MIPS_LOCAL 0x10000000
-+
-+/* Legal values for d_tag field of Elf32_Dyn. */
-+
-+#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
-+#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
-+#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
-+#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
-+#define DT_MIPS_FLAGS 0x70000005 /* Flags */
-+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
-+#define DT_MIPS_MSYM 0x70000007
-+#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
-+#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
-+#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
-+#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
-+#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
-+#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
-+#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
-+#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
-+#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
-+#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
-+#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
-+#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
-+ DT_MIPS_DELTA_CLASS. */
-+#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
-+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
-+ DT_MIPS_DELTA_INSTANCE. */
-+#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
-+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
-+ DT_MIPS_DELTA_RELOC. */
-+#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
-+ relocations refer to. */
-+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
-+ DT_MIPS_DELTA_SYM. */
-+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
-+ class declaration. */
-+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
-+ DT_MIPS_DELTA_CLASSSYM. */
-+#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
-+#define DT_MIPS_PIXIE_INIT 0x70000023
-+#define DT_MIPS_SYMBOL_LIB 0x70000024
-+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
-+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
-+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
-+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
-+#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
-+#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
-+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
-+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
-+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
-+ function stored in GOT. */
-+#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added
-+ by rld on dlopen() calls. */
-+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
-+#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
-+#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
-+#define DT_MIPS_NUM 0x32
-+
-+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
-+
-+#define RHF_NONE 0 /* No flags */
-+#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
-+#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
-+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
-+#define RHF_NO_MOVE (1 << 3)
-+#define RHF_SGI_ONLY (1 << 4)
-+#define RHF_GUARANTEE_INIT (1 << 5)
-+#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
-+#define RHF_GUARANTEE_START_INIT (1 << 7)
-+#define RHF_PIXIE (1 << 8)
-+#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
-+#define RHF_REQUICKSTART (1 << 10)
-+#define RHF_REQUICKSTARTED (1 << 11)
-+#define RHF_CORD (1 << 12)
-+#define RHF_NO_UNRES_UNDEF (1 << 13)
-+#define RHF_RLD_ORDER_SAFE (1 << 14)
-+
-+/* Entries found in sections of type SHT_MIPS_LIBLIST. */
-+
-+typedef struct
-+{
-+ Elf32_Word l_name; /* Name (string table index) */
-+ Elf32_Word l_time_stamp; /* Timestamp */
-+ Elf32_Word l_checksum; /* Checksum */
-+ Elf32_Word l_version; /* Interface version */
-+ Elf32_Word l_flags; /* Flags */
-+} Elf32_Lib;
-+
-+typedef struct
-+{
-+ Elf64_Word l_name; /* Name (string table index) */
-+ Elf64_Word l_time_stamp; /* Timestamp */
-+ Elf64_Word l_checksum; /* Checksum */
-+ Elf64_Word l_version; /* Interface version */
-+ Elf64_Word l_flags; /* Flags */
-+} Elf64_Lib;
-+
-+
-+/* Legal values for l_flags. */
-+
-+#define LL_NONE 0
-+#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
-+#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
-+#define LL_REQUIRE_MINOR (1 << 2)
-+#define LL_EXPORTS (1 << 3)
-+#define LL_DELAY_LOAD (1 << 4)
-+#define LL_DELTA (1 << 5)
-+
-+/* Entries found in sections of type SHT_MIPS_CONFLICT. */
-+
-+typedef Elf32_Addr Elf32_Conflict;
-+
-+
-+/* HPPA specific definitions. */
-+
-+/* Legal values for e_flags field of Elf32_Ehdr. */
-+
-+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
-+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
-+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
-+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
-+#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
-+ prediction. */
-+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
-+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
-+
-+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
-+
-+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
-+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
-+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
-+
-+/* Additional section indeces. */
-+
-+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
-+ symbols in ANSI C. */
-+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
-+
-+/* Legal values for sh_type field of Elf32_Shdr. */
-+
-+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
-+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
-+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
-+
-+/* Legal values for sh_flags field of Elf32_Shdr. */
-+
-+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
-+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
-+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
-+
-+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
-+
-+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
-+
-+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
-+#define STT_HP_STUB (STT_LOOS + 0x2)
-+
-+/* HPPA relocs. */
-+
-+#define R_PARISC_NONE 0 /* No reloc. */
-+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
-+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
-+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
-+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
-+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
-+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
-+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
-+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
-+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
-+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
-+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
-+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
-+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
-+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
-+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
-+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
-+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
-+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
-+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
-+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
-+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
-+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
-+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
-+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
-+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
-+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
-+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
-+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
-+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
-+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
-+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
-+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
-+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
-+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
-+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
-+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
-+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
-+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
-+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
-+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
-+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
-+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
-+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
-+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
-+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
-+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
-+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
-+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
-+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
-+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
-+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
-+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
-+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
-+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
-+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
-+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
-+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
-+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
-+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
-+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
-+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
-+#define R_PARISC_LORESERVE 128
-+#define R_PARISC_COPY 128 /* Copy relocation. */
-+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
-+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
-+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
-+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
-+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
-+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
-+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
-+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
-+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
-+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
-+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
-+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
-+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
-+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
-+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
-+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
-+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
-+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
-+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
-+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
-+#define R_PARISC_HIRESERVE 255
-+
-+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
-+
-+#define PT_HP_TLS (PT_LOOS + 0x0)
-+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
-+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
-+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
-+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
-+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
-+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
-+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
-+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
-+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
-+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
-+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
-+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
-+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
-+#define PT_HP_STACK (PT_LOOS + 0x14)
-+
-+#define PT_PARISC_ARCHEXT 0x70000000
-+#define PT_PARISC_UNWIND 0x70000001
-+
-+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
-+
-+#define PF_PARISC_SBP 0x08000000
-+
-+#define PF_HP_PAGE_SIZE 0x00100000
-+#define PF_HP_FAR_SHARED 0x00200000
-+#define PF_HP_NEAR_SHARED 0x00400000
-+#define PF_HP_CODE 0x01000000
-+#define PF_HP_MODIFY 0x02000000
-+#define PF_HP_LAZYSWAP 0x04000000
-+#define PF_HP_SBP 0x08000000
-+
-+
-+/* Alpha specific definitions. */
-+
-+/* Legal values for e_flags field of Elf64_Ehdr. */
-+
-+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
-+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
-+
-+/* Legal values for sh_type field of Elf64_Shdr. */
-+
-+/* These two are primerily concerned with ECOFF debugging info. */
-+#define SHT_ALPHA_DEBUG 0x70000001
-+#define SHT_ALPHA_REGINFO 0x70000002
-+
-+/* Legal values for sh_flags field of Elf64_Shdr. */
-+
-+#define SHF_ALPHA_GPREL 0x10000000
-+
-+/* Legal values for st_other field of Elf64_Sym. */
-+#define STO_ALPHA_NOPV 0x80 /* No PV required. */
-+#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
-+
-+/* Alpha relocs. */
-+
-+#define R_ALPHA_NONE 0 /* No reloc */
-+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
-+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
-+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
-+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
-+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
-+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
-+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
-+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
-+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
-+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
-+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
-+#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
-+#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
-+#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
-+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
-+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
-+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
-+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
-+#define R_ALPHA_TLS_GD_HI 28
-+#define R_ALPHA_TLSGD 29
-+#define R_ALPHA_TLS_LDM 30
-+#define R_ALPHA_DTPMOD64 31
-+#define R_ALPHA_GOTDTPREL 32
-+#define R_ALPHA_DTPREL64 33
-+#define R_ALPHA_DTPRELHI 34
-+#define R_ALPHA_DTPRELLO 35
-+#define R_ALPHA_DTPREL16 36
-+#define R_ALPHA_GOTTPREL 37
-+#define R_ALPHA_TPREL64 38
-+#define R_ALPHA_TPRELHI 39
-+#define R_ALPHA_TPRELLO 40
-+#define R_ALPHA_TPREL16 41
-+/* Keep this the last entry. */
-+#define R_ALPHA_NUM 46
-+
-+/* Magic values of the LITUSE relocation addend. */
-+#define LITUSE_ALPHA_ADDR 0
-+#define LITUSE_ALPHA_BASE 1
-+#define LITUSE_ALPHA_BYTOFF 2
-+#define LITUSE_ALPHA_JSR 3
-+#define LITUSE_ALPHA_TLS_GD 4
-+#define LITUSE_ALPHA_TLS_LDM 5
-+
-+
-+/* PowerPC specific declarations */
-+
-+/* Values for Elf32/64_Ehdr.e_flags. */
-+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
-+
-+/* Cygnus local bits below */
-+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
-+#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
-+ flag */
-+
-+/* PowerPC relocations defined by the ABIs */
-+#define R_PPC_NONE 0
-+#define R_PPC_ADDR32 1 /* 32bit absolute address */
-+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
-+#define R_PPC_ADDR16 3 /* 16bit absolute address */
-+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
-+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
-+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
-+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
-+#define R_PPC_ADDR14_BRTAKEN 8
-+#define R_PPC_ADDR14_BRNTAKEN 9
-+#define R_PPC_REL24 10 /* PC relative 26 bit */
-+#define R_PPC_REL14 11 /* PC relative 16 bit */
-+#define R_PPC_REL14_BRTAKEN 12
-+#define R_PPC_REL14_BRNTAKEN 13
-+#define R_PPC_GOT16 14
-+#define R_PPC_GOT16_LO 15
-+#define R_PPC_GOT16_HI 16
-+#define R_PPC_GOT16_HA 17
-+#define R_PPC_PLTREL24 18
-+#define R_PPC_COPY 19
-+#define R_PPC_GLOB_DAT 20
-+#define R_PPC_JMP_SLOT 21
-+#define R_PPC_RELATIVE 22
-+#define R_PPC_LOCAL24PC 23
-+#define R_PPC_UADDR32 24
-+#define R_PPC_UADDR16 25
-+#define R_PPC_REL32 26
-+#define R_PPC_PLT32 27
-+#define R_PPC_PLTREL32 28
-+#define R_PPC_PLT16_LO 29
-+#define R_PPC_PLT16_HI 30
-+#define R_PPC_PLT16_HA 31
-+#define R_PPC_SDAREL16 32
-+#define R_PPC_SECTOFF 33
-+#define R_PPC_SECTOFF_LO 34
-+#define R_PPC_SECTOFF_HI 35
-+#define R_PPC_SECTOFF_HA 36
-+
-+/* PowerPC relocations defined for the TLS access ABI. */
-+#define R_PPC_TLS 67 /* none (sym+add)@tls */
-+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
-+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
-+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
-+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
-+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
-+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
-+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
-+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
-+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
-+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
-+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
-+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
-+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
-+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
-+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
-+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
-+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
-+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
-+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
-+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
-+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
-+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
-+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
-+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
-+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
-+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
-+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
-+
-+/* Keep this the last entry. */
-+#define R_PPC_NUM 95
-+
-+/* The remaining relocs are from the Embedded ELF ABI, and are not
-+ in the SVR4 ELF ABI. */
-+#define R_PPC_EMB_NADDR32 101
-+#define R_PPC_EMB_NADDR16 102
-+#define R_PPC_EMB_NADDR16_LO 103
-+#define R_PPC_EMB_NADDR16_HI 104
-+#define R_PPC_EMB_NADDR16_HA 105
-+#define R_PPC_EMB_SDAI16 106
-+#define R_PPC_EMB_SDA2I16 107
-+#define R_PPC_EMB_SDA2REL 108
-+#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
-+#define R_PPC_EMB_MRKREF 110
-+#define R_PPC_EMB_RELSEC16 111
-+#define R_PPC_EMB_RELST_LO 112
-+#define R_PPC_EMB_RELST_HI 113
-+#define R_PPC_EMB_RELST_HA 114
-+#define R_PPC_EMB_BIT_FLD 115
-+#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
-+
-+/* Diab tool relocations. */
-+#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
-+#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
-+#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
-+#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
-+#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
-+#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
-+
-+/* This is a phony reloc to handle any old fashioned TOC16 references
-+ that may still be in object files. */
-+#define R_PPC_TOC16 255
-+
-+
-+/* PowerPC64 relocations defined by the ABIs */
-+#define R_PPC64_NONE R_PPC_NONE
-+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
-+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
-+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
-+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
-+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
-+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
-+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
-+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
-+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
-+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
-+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
-+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
-+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
-+#define R_PPC64_GOT16 R_PPC_GOT16
-+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
-+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
-+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
-+
-+#define R_PPC64_COPY R_PPC_COPY
-+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
-+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
-+#define R_PPC64_RELATIVE R_PPC_RELATIVE
-+
-+#define R_PPC64_UADDR32 R_PPC_UADDR32
-+#define R_PPC64_UADDR16 R_PPC_UADDR16
-+#define R_PPC64_REL32 R_PPC_REL32
-+#define R_PPC64_PLT32 R_PPC_PLT32
-+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
-+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
-+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
-+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
-+
-+#define R_PPC64_SECTOFF R_PPC_SECTOFF
-+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
-+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
-+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
-+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
-+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
-+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
-+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
-+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
-+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
-+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
-+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
-+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
-+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
-+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
-+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
-+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
-+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
-+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
-+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
-+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
-+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
-+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
-+
-+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
-+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
-+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
-+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
-+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
-+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
-+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
-+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
-+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
-+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
-+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
-+
-+/* PowerPC64 relocations defined for the TLS access ABI. */
-+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
-+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
-+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
-+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
-+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
-+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
-+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
-+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
-+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
-+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
-+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
-+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
-+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
-+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
-+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
-+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
-+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
-+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
-+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
-+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
-+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
-+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
-+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
-+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
-+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
-+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
-+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
-+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
-+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
-+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
-+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
-+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
-+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
-+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
-+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
-+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
-+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
-+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
-+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
-+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
-+
-+/* Keep this the last entry. */
-+#define R_PPC64_NUM 107
-+
-+/* PowerPC64 specific values for the Dyn d_tag field. */
-+#define DT_PPC64_GLINK (DT_LOPROC + 0)
-+#define DT_PPC64_NUM 1
-+
-+
-+/* ARM specific declarations */
-+
-+/* Processor specific flags for the ELF header e_flags field. */
-+#define EF_ARM_RELEXEC 0x01
-+#define EF_ARM_HASENTRY 0x02
-+#define EF_ARM_INTERWORK 0x04
-+#define EF_ARM_APCS_26 0x08
-+#define EF_ARM_APCS_FLOAT 0x10
-+#define EF_ARM_PIC 0x20
-+#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
-+#define EF_ARM_NEW_ABI 0x80
-+#define EF_ARM_OLD_ABI 0x100
-+
-+/* Other constants defined in the ARM ELF spec. version B-01. */
-+/* NB. These conflict with values defined above. */
-+#define EF_ARM_SYMSARESORTED 0x04
-+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
-+#define EF_ARM_MAPSYMSFIRST 0x10
-+#define EF_ARM_EABIMASK 0XFF000000
-+
-+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
-+#define EF_ARM_EABI_UNKNOWN 0x00000000
-+#define EF_ARM_EABI_VER1 0x01000000
-+#define EF_ARM_EABI_VER2 0x02000000
-+
-+/* Additional symbol types for Thumb */
-+#define STT_ARM_TFUNC 0xd
-+
-+/* ARM-specific values for sh_flags */
-+#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
-+#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
-+ in the input to a link step */
-+
-+/* ARM-specific program header flags */
-+#define PF_ARM_SB 0x10000000 /* Segment contains the location
-+ addressed by the static base */
-+
-+/* ARM relocs. */
-+#define R_ARM_NONE 0 /* No reloc */
-+#define R_ARM_PC24 1 /* PC relative 26 bit branch */
-+#define R_ARM_ABS32 2 /* Direct 32 bit */
-+#define R_ARM_REL32 3 /* PC relative 32 bit */
-+#define R_ARM_PC13 4
-+#define R_ARM_ABS16 5 /* Direct 16 bit */
-+#define R_ARM_ABS12 6 /* Direct 12 bit */
-+#define R_ARM_THM_ABS5 7
-+#define R_ARM_ABS8 8 /* Direct 8 bit */
-+#define R_ARM_SBREL32 9
-+#define R_ARM_THM_PC22 10
-+#define R_ARM_THM_PC8 11
-+#define R_ARM_AMP_VCALL9 12
-+#define R_ARM_SWI24 13
-+#define R_ARM_THM_SWI8 14
-+#define R_ARM_XPC25 15
-+#define R_ARM_THM_XPC22 16
-+#define R_ARM_COPY 20 /* Copy symbol at runtime */
-+#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
-+#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
-+#define R_ARM_RELATIVE 23 /* Adjust by program base */
-+#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
-+#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
-+#define R_ARM_GOT32 26 /* 32 bit GOT entry */
-+#define R_ARM_PLT32 27 /* 32 bit PLT address */
-+#define R_ARM_ALU_PCREL_7_0 32
-+#define R_ARM_ALU_PCREL_15_8 33
-+#define R_ARM_ALU_PCREL_23_15 34
-+#define R_ARM_LDR_SBREL_11_0 35
-+#define R_ARM_ALU_SBREL_19_12 36
-+#define R_ARM_ALU_SBREL_27_20 37
-+#define R_ARM_GNU_VTENTRY 100
-+#define R_ARM_GNU_VTINHERIT 101
-+#define R_ARM_THM_PC11 102 /* thumb unconditional branch */
-+#define R_ARM_THM_PC9 103 /* thumb conditional branch */
-+#define R_ARM_RXPC25 249
-+#define R_ARM_RSBREL32 250
-+#define R_ARM_THM_RPC22 251
-+#define R_ARM_RREL32 252
-+#define R_ARM_RABS22 253
-+#define R_ARM_RPC24 254
-+#define R_ARM_RBASE 255
-+/* Keep this the last entry. */
-+#define R_ARM_NUM 256
-+
-+/* IA-64 specific declarations. */
-+
-+/* Processor specific flags for the Ehdr e_flags field. */
-+#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
-+#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
-+#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
-+
-+/* Processor specific values for the Phdr p_type field. */
-+#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
-+#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
-+
-+/* Processor specific flags for the Phdr p_flags field. */
-+#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
-+
-+/* Processor specific values for the Shdr sh_type field. */
-+#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
-+#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
-+
-+/* Processor specific flags for the Shdr sh_flags field. */
-+#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
-+#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
-+
-+/* Processor specific values for the Dyn d_tag field. */
-+#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
-+#define DT_IA_64_NUM 1
-+
-+/* IA-64 relocations. */
-+#define R_IA64_NONE 0x00 /* none */
-+#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
-+#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
-+#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
-+#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
-+#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
-+#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
-+#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
-+#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
-+#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
-+#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
-+#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
-+#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
-+#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
-+#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
-+#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
-+#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
-+#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
-+#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
-+#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
-+#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
-+#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
-+#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
-+#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
-+#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
-+#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
-+#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
-+#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
-+#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
-+#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
-+#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
-+#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
-+#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
-+#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
-+#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
-+#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
-+#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
-+#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
-+#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
-+#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
-+#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
-+#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
-+#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
-+#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
-+#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
-+#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
-+#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
-+#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
-+#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
-+#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
-+#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
-+#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
-+#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
-+#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
-+#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
-+#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
-+#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
-+#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
-+#define R_IA64_COPY 0x84 /* copy relocation */
-+#define R_IA64_SUB 0x85 /* Addend and symbol difference */
-+#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
-+#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
-+#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
-+#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
-+#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
-+#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
-+#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
-+#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
-+#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
-+#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
-+#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
-+#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
-+#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
-+#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
-+#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
-+#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
-+#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
-+
-+/* SH specific declarations */
-+
-+/* SH relocs. */
-+#define R_SH_NONE 0
-+#define R_SH_DIR32 1
-+#define R_SH_REL32 2
-+#define R_SH_DIR8WPN 3
-+#define R_SH_IND12W 4
-+#define R_SH_DIR8WPL 5
-+#define R_SH_DIR8WPZ 6
-+#define R_SH_DIR8BP 7
-+#define R_SH_DIR8W 8
-+#define R_SH_DIR8L 9
-+#define R_SH_SWITCH16 25
-+#define R_SH_SWITCH32 26
-+#define R_SH_USES 27
-+#define R_SH_COUNT 28
-+#define R_SH_ALIGN 29
-+#define R_SH_CODE 30
-+#define R_SH_DATA 31
-+#define R_SH_LABEL 32
-+#define R_SH_SWITCH8 33
-+#define R_SH_GNU_VTINHERIT 34
-+#define R_SH_GNU_VTENTRY 35
-+#define R_SH_TLS_GD_32 144
-+#define R_SH_TLS_LD_32 145
-+#define R_SH_TLS_LDO_32 146
-+#define R_SH_TLS_IE_32 147
-+#define R_SH_TLS_LE_32 148
-+#define R_SH_TLS_DTPMOD32 149
-+#define R_SH_TLS_DTPOFF32 150
-+#define R_SH_TLS_TPOFF32 151
-+#define R_SH_GOT32 160
-+#define R_SH_PLT32 161
-+#define R_SH_COPY 162
-+#define R_SH_GLOB_DAT 163
-+#define R_SH_JMP_SLOT 164
-+#define R_SH_RELATIVE 165
-+#define R_SH_GOTOFF 166
-+#define R_SH_GOTPC 167
-+/* Keep this the last entry. */
-+#define R_SH_NUM 256
-+
-+/* Additional s390 relocs */
-+
-+#define R_390_NONE 0 /* No reloc. */
-+#define R_390_8 1 /* Direct 8 bit. */
-+#define R_390_12 2 /* Direct 12 bit. */
-+#define R_390_16 3 /* Direct 16 bit. */
-+#define R_390_32 4 /* Direct 32 bit. */
-+#define R_390_PC32 5 /* PC relative 32 bit. */
-+#define R_390_GOT12 6 /* 12 bit GOT offset. */
-+#define R_390_GOT32 7 /* 32 bit GOT offset. */
-+#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
-+#define R_390_COPY 9 /* Copy symbol at runtime. */
-+#define R_390_GLOB_DAT 10 /* Create GOT entry. */
-+#define R_390_JMP_SLOT 11 /* Create PLT entry. */
-+#define R_390_RELATIVE 12 /* Adjust by program base. */
-+#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
-+#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
-+#define R_390_GOT16 15 /* 16 bit GOT offset. */
-+#define R_390_PC16 16 /* PC relative 16 bit. */
-+#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
-+#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
-+#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
-+#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
-+#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
-+#define R_390_64 22 /* Direct 64 bit. */
-+#define R_390_PC64 23 /* PC relative 64 bit. */
-+#define R_390_GOT64 24 /* 64 bit GOT offset. */
-+#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
-+#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
-+#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
-+#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
-+#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
-+#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
-+#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
-+#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
-+#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
-+#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
-+#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
-+#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
-+#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
-+#define R_390_TLS_GDCALL 38 /* Tag for function call in general
-+ dynamic TLS code. */
-+#define R_390_TLS_LDCALL 39 /* Tag for function call in local
-+ dynamic TLS code. */
-+#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
-+ thread local data. */
-+#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
-+ thread local data. */
-+#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
-+ block offset. */
-+#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
-+ thread local data in LE code. */
-+#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
-+ thread local data in LE code. */
-+#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
-+ negated static TLS block offset. */
-+#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
-+ negated static TLS block offset. */
-+#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
-+ negated static TLS block offset. */
-+#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
-+ static TLS block. */
-+#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
-+ static TLS block. */
-+#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
-+ block. */
-+#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
-+ block. */
-+#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
-+#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
-+#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS
-+ block. */
-+
-+/* Keep this the last entry. */
-+#define R_390_NUM 57
-+
-+/* CRIS relocations. */
-+#define R_CRIS_NONE 0
-+#define R_CRIS_8 1
-+#define R_CRIS_16 2
-+#define R_CRIS_32 3
-+#define R_CRIS_8_PCREL 4
-+#define R_CRIS_16_PCREL 5
-+#define R_CRIS_32_PCREL 6
-+#define R_CRIS_GNU_VTINHERIT 7
-+#define R_CRIS_GNU_VTENTRY 8
-+#define R_CRIS_COPY 9
-+#define R_CRIS_GLOB_DAT 10
-+#define R_CRIS_JUMP_SLOT 11
-+#define R_CRIS_RELATIVE 12
-+#define R_CRIS_16_GOT 13
-+#define R_CRIS_32_GOT 14
-+#define R_CRIS_16_GOTPLT 15
-+#define R_CRIS_32_GOTPLT 16
-+#define R_CRIS_32_GOTREL 17
-+#define R_CRIS_32_PLT_GOTREL 18
-+#define R_CRIS_32_PLT_PCREL 19
-+
-+#define R_CRIS_NUM 20
-+
-+/* AMD x86-64 relocations. */
-+#define R_X86_64_NONE 0 /* No reloc */
-+#define R_X86_64_64 1 /* Direct 64 bit */
-+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
-+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
-+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
-+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
-+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
-+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
-+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
-+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
-+ offset to GOT */
-+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
-+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
-+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
-+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
-+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
-+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
-+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
-+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
-+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
-+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
-+ to two GOT entries for GD symbol */
-+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
-+ to two GOT entries for LD symbol */
-+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
-+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
-+ to GOT entry for IE symbol */
-+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
-+
-+#define R_X86_64_NUM 24
-+
-+__END_DECLS
-+
-+#endif /* elf.h */
-
- #include "elfconfig.h"
-
-@@ -185,3 +2631,4 @@
- void fatal(const char *fmt, ...);
- void warn(const char *fmt, ...);
- void merror(const char *fmt, ...);
-+
-diff -Nur linux-3.11.5.orig/scripts/mod/sumversion.c linux-3.11.5/scripts/mod/sumversion.c
---- linux-3.11.5.orig/scripts/mod/sumversion.c 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/scripts/mod/sumversion.c 2013-10-16 18:09:31.000000000 +0200
-@@ -1,4 +1,4 @@
--#include <netinet/in.h>
-+/* #include <netinet/in.h> */
- #ifdef __sun__
- #include <inttypes.h>
- #else
-diff -Nur linux-3.11.5.orig/tools/include/tools/linux_types.h linux-3.11.5/tools/include/tools/linux_types.h
---- linux-3.11.5.orig/tools/include/tools/linux_types.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.11.5/tools/include/tools/linux_types.h 2013-10-16 18:09:31.000000000 +0200
-@@ -0,0 +1,22 @@
-+#ifndef __LINUX_TYPES_H
-+#define __LINUX_TYPES_H
-+
-+#include <stdint.h>
-+
-+typedef uint8_t __u8;
-+typedef uint8_t __be8;
-+typedef uint8_t __le8;
-+
-+typedef uint16_t __u16;
-+typedef uint16_t __be16;
-+typedef uint16_t __le16;
-+
-+typedef uint32_t __u32;
-+typedef uint32_t __be32;
-+typedef uint32_t __le32;
-+
-+typedef uint64_t __u64;
-+typedef uint64_t __be64;
-+typedef uint64_t __le64;
-+
-+#endif
diff --git a/target/linux/patches/3.12.18/defaults.patch b/target/linux/patches/3.12.18/defaults.patch
deleted file mode 100644
index 6cdca084e..000000000
--- a/target/linux/patches/3.12.18/defaults.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-diff -Nur linux-3.0.4.orig/fs/Kconfig linux-3.0.4/fs/Kconfig
---- linux-3.0.4.orig/fs/Kconfig 2011-08-29 22:56:30.000000000 +0200
-+++ linux-3.0.4/fs/Kconfig 2011-10-15 22:08:44.000000000 +0200
-@@ -47,7 +47,7 @@
- def_bool n
-
- config EXPORTFS
-- tristate
-+ def_bool y
-
- config FILE_LOCKING
- bool "Enable POSIX file locking API" if EXPERT
-diff -Nur linux-3.0.4.orig/fs/notify/Kconfig linux-3.0.4/fs/notify/Kconfig
---- linux-3.0.4.orig/fs/notify/Kconfig 2011-08-29 22:56:30.000000000 +0200
-+++ linux-3.0.4/fs/notify/Kconfig 2011-10-15 22:02:00.000000000 +0200
-@@ -1,5 +1,5 @@
- config FSNOTIFY
-- def_bool n
-+ def_bool y
-
- source "fs/notify/dnotify/Kconfig"
- source "fs/notify/inotify/Kconfig"
-diff -Nur linux-3.11.10.orig/drivers/scsi/Kconfig linux-3.11.10/drivers/scsi/Kconfig
---- linux-3.11.10.orig/drivers/scsi/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/scsi/Kconfig 2013-12-27 19:13:21.000000000 +0100
-@@ -2,7 +2,7 @@
-
- config SCSI_MOD
- tristate
-- default y if SCSI=n || SCSI=y
-+ default y if SCSI=y
- default m if SCSI=m
-
- config RAID_ATTRS
-diff -Nur linux-3.11.10.orig/usr/Kconfig linux-3.11.10/usr/Kconfig
---- linux-3.11.10.orig/usr/Kconfig 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/usr/Kconfig 2013-12-27 19:15:16.000000000 +0100
-@@ -47,7 +47,7 @@
-
- config RD_GZIP
- bool "Support initial ramdisks compressed using gzip" if EXPERT
-- default y
-+ default n
- depends on BLK_DEV_INITRD
- select DECOMPRESS_GZIP
- help
diff --git a/target/linux/patches/3.12.18/disable-netfilter.patch b/target/linux/patches/3.12.18/disable-netfilter.patch
deleted file mode 100644
index 7b1ca013a..000000000
--- a/target/linux/patches/3.12.18/disable-netfilter.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-diff -Nur linux-3.7.3.orig/net/Kconfig linux-3.7.3/net/Kconfig
---- linux-3.7.3.orig/net/Kconfig 2013-01-17 17:47:40.000000000 +0100
-+++ linux-3.7.3/net/Kconfig 2013-01-19 18:19:55.000000000 +0100
-@@ -163,7 +163,7 @@
- config NETFILTER_ADVANCED
- bool "Advanced netfilter configuration"
- depends on NETFILTER
-- default y
-+ default n
- help
- If you say Y here you can select between all the netfilter modules.
- If you say N the more unusual ones will not be shown and the
-@@ -175,7 +175,7 @@
- bool "Bridged IP/ARP packets filtering"
- depends on BRIDGE && NETFILTER && INET
- depends on NETFILTER_ADVANCED
-- default y
-+ default n
- ---help---
- Enabling this option will let arptables resp. iptables see bridged
- ARP resp. IP traffic. If you want a bridging firewall, you probably
-diff -Nur linux-3.7.3.orig/net/netfilter/Kconfig linux-3.7.3/net/netfilter/Kconfig
---- linux-3.7.3.orig/net/netfilter/Kconfig 2013-01-17 17:47:40.000000000 +0100
-+++ linux-3.7.3/net/netfilter/Kconfig 2013-01-19 18:21:41.000000000 +0100
-@@ -22,7 +22,6 @@
-
- config NETFILTER_NETLINK_LOG
- tristate "Netfilter LOG over NFNETLINK interface"
-- default m if NETFILTER_ADVANCED=n
- select NETFILTER_NETLINK
- help
- If this option is enabled, the kernel will include support
-@@ -34,7 +33,6 @@
-
- config NF_CONNTRACK
- tristate "Netfilter connection tracking support"
-- default m if NETFILTER_ADVANCED=n
- help
- Connection tracking keeps a record of what packets have passed
- through your machine, in order to figure out how they are related
-@@ -60,7 +58,6 @@
- config NF_CONNTRACK_SECMARK
- bool 'Connection tracking security mark support'
- depends on NETWORK_SECMARK
-- default m if NETFILTER_ADVANCED=n
- help
- This option enables security markings to be applied to
- connections. Typically they are copied to connections from
-@@ -177,7 +174,6 @@
-
- config NF_CONNTRACK_FTP
- tristate "FTP protocol support"
-- default m if NETFILTER_ADVANCED=n
- help
- Tracking FTP connections is problematic: special helpers are
- required for tracking them, and doing masquerading and other forms
-@@ -211,7 +207,6 @@
-
- config NF_CONNTRACK_IRC
- tristate "IRC protocol support"
-- default m if NETFILTER_ADVANCED=n
- help
- There is a commonly-used extension to IRC called
- Direct Client-to-Client Protocol (DCC). This enables users to send
-@@ -296,7 +291,6 @@
-
- config NF_CONNTRACK_SIP
- tristate "SIP protocol support"
-- default m if NETFILTER_ADVANCED=n
- help
- SIP is an application-layer control protocol that can establish,
- modify, and terminate multimedia sessions (conferences) such as
-@@ -320,7 +314,6 @@
- config NF_CT_NETLINK
- tristate 'Connection tracking netlink interface'
- select NETFILTER_NETLINK
-- default m if NETFILTER_ADVANCED=n
- help
- This option enables support for a netlink-based userspace interface
-
-@@ -424,7 +417,6 @@
-
- config NETFILTER_XTABLES
- tristate "Netfilter Xtables support (required for ip_tables)"
-- default m if NETFILTER_ADVANCED=n
- help
- This is required if you intend to use any of ip_tables,
- ip6_tables or arp_tables.
-@@ -435,7 +427,6 @@
-
- config NETFILTER_XT_MARK
- tristate 'nfmark target and match support'
-- default m if NETFILTER_ADVANCED=n
- ---help---
- This option adds the "MARK" target and "mark" match.
-
-@@ -527,7 +518,6 @@
- config NETFILTER_XT_TARGET_CONNSECMARK
- tristate '"CONNSECMARK" target support'
- depends on NF_CONNTRACK && NF_CONNTRACK_SECMARK
-- default m if NETFILTER_ADVANCED=n
- help
- The CONNSECMARK target copies security markings from packets
- to connections, and restores security markings from connections
-@@ -632,7 +622,6 @@
-
- config NETFILTER_XT_TARGET_LOG
- tristate "LOG target support"
-- default m if NETFILTER_ADVANCED=n
- help
- This option adds a `LOG' target, which allows you to create rules in
- any iptables table which records the packet header to the syslog.
-@@ -660,7 +649,6 @@
-
- config NETFILTER_XT_TARGET_NFLOG
- tristate '"NFLOG" target support'
-- default m if NETFILTER_ADVANCED=n
- select NETFILTER_NETLINK_LOG
- help
- This option enables the NFLOG target, which allows to LOG
-@@ -741,7 +729,6 @@
- config NETFILTER_XT_TARGET_SECMARK
- tristate '"SECMARK" target support'
- depends on NETWORK_SECMARK
-- default m if NETFILTER_ADVANCED=n
- help
- The SECMARK target allows security marking of network
- packets, for use with security subsystems.
-@@ -751,7 +738,6 @@
- config NETFILTER_XT_TARGET_TCPMSS
- tristate '"TCPMSS" target support'
- depends on (IPV6 || IPV6=n)
-- default m if NETFILTER_ADVANCED=n
- ---help---
- This option adds a `TCPMSS' target, which allows you to alter the
- MSS value of TCP SYN packets, to control the maximum size for that
-@@ -856,7 +842,6 @@
- config NETFILTER_XT_MATCH_CONNTRACK
- tristate '"conntrack" connection tracking match support'
- depends on NF_CONNTRACK
-- default m if NETFILTER_ADVANCED=n
- help
- This is a general conntrack match module, a superset of the state match.
-
-@@ -1063,7 +1048,6 @@
- config NETFILTER_XT_MATCH_POLICY
- tristate 'IPsec "policy" match support'
- depends on XFRM
-- default m if NETFILTER_ADVANCED=n
- help
- Policy matching allows you to match packets based on the
- IPsec policy that was used during decapsulation/will
-@@ -1170,7 +1154,6 @@
- config NETFILTER_XT_MATCH_STATE
- tristate '"state" match support'
- depends on NF_CONNTRACK
-- default m if NETFILTER_ADVANCED=n
- help
- Connection state matching allows you to match packets based on their
- relationship to a tracked connection (ie. previous packets). This
diff --git a/target/linux/patches/3.12.18/export-symbol-for-exmap.patch b/target/linux/patches/3.12.18/export-symbol-for-exmap.patch
deleted file mode 100644
index 4f0fc8449..000000000
--- a/target/linux/patches/3.12.18/export-symbol-for-exmap.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -Nur linux-3.11.5.orig/kernel/pid.c linux-3.11.5/kernel/pid.c
---- linux-3.11.5.orig/kernel/pid.c 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/kernel/pid.c 2013-10-29 15:37:02.000000000 +0100
-@@ -450,6 +450,7 @@
- {
- return find_task_by_pid_ns(vnr, task_active_pid_ns(current));
- }
-+EXPORT_SYMBOL(find_task_by_vpid);
-
- struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
- {
diff --git a/target/linux/patches/3.12.18/microblaze-ethernet.patch b/target/linux/patches/3.12.18/microblaze-ethernet.patch
deleted file mode 100644
index 742ab477e..000000000
--- a/target/linux/patches/3.12.18/microblaze-ethernet.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -Nur linux-3.11.10.orig/drivers/net/ethernet/xilinx/xilinx_emaclite.c linux-3.11.10/drivers/net/ethernet/xilinx/xilinx_emaclite.c
---- linux-3.11.10.orig/drivers/net/ethernet/xilinx/xilinx_emaclite.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/drivers/net/ethernet/xilinx/xilinx_emaclite.c 2013-12-23 20:01:14.000000000 +0100
-@@ -1282,6 +1282,7 @@
- { .compatible = "xlnx,opb-ethernetlite-1.01.b", },
- { .compatible = "xlnx,xps-ethernetlite-1.00.a", },
- { .compatible = "xlnx,xps-ethernetlite-2.00.a", },
-+ { .compatible = "xlnx,xps-ethernetlite-2.00.b", },
- { .compatible = "xlnx,xps-ethernetlite-2.01.a", },
- { .compatible = "xlnx,xps-ethernetlite-3.00.a", },
- { /* end of list */ },
diff --git a/target/linux/patches/3.12.18/microblaze-setup.patch b/target/linux/patches/3.12.18/microblaze-setup.patch
deleted file mode 100644
index 43815f274..000000000
--- a/target/linux/patches/3.12.18/microblaze-setup.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Nur linux-3.11.10.orig/arch/microblaze/kernel/setup.c linux-3.11.10/arch/microblaze/kernel/setup.c
---- linux-3.11.10.orig/arch/microblaze/kernel/setup.c 2013-11-29 19:42:37.000000000 +0100
-+++ linux-3.11.10/arch/microblaze/kernel/setup.c 2013-12-08 13:02:37.000000000 +0100
-@@ -177,7 +177,7 @@
- #else
- if (!msr) {
- pr_info("!!!Your kernel not setup MSR instruction but ");
-- pr_cont"CPU have it %x\n", msr);
-+ pr_cont("CPU have it %x\n", msr);
- }
- #endif
-
diff --git a/target/linux/patches/3.12.18/mips-lzo-fix.patch b/target/linux/patches/3.12.18/mips-lzo-fix.patch
deleted file mode 100644
index 0740bdc6a..000000000
--- a/target/linux/patches/3.12.18/mips-lzo-fix.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Nur linux-3.11.5.orig/arch/mips/boot/compressed/decompress.c linux-3.11.5/arch/mips/boot/compressed/decompress.c
---- linux-3.11.5.orig/arch/mips/boot/compressed/decompress.c 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/arch/mips/boot/compressed/decompress.c 2013-11-08 18:19:47.000000000 +0100
-@@ -43,7 +43,7 @@
- /* activate the code for pre-boot environment */
- #define STATIC static
-
--#ifdef CONFIG_KERNEL_GZIP
-+#if defined(CONFIG_KERNEL_GZIP) || defined(CONFIG_KERNEL_LZO)
- void *memcpy(void *dest, const void *src, size_t n)
- {
- int i;
diff --git a/target/linux/patches/3.12.18/mtd-rootfs.patch b/target/linux/patches/3.12.18/mtd-rootfs.patch
deleted file mode 100644
index 775d5fc80..000000000
--- a/target/linux/patches/3.12.18/mtd-rootfs.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff -Nur linux-3.5.orig//drivers/mtd/mtdpart.c linux-3.5/drivers/mtd/mtdpart.c
---- linux-3.5.orig//drivers/mtd/mtdpart.c 2012-07-21 22:58:29.000000000 +0200
-+++ linux-3.5/drivers/mtd/mtdpart.c 2012-07-31 23:59:07.000000000 +0200
-@@ -30,6 +30,7 @@
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
- #include <linux/err.h>
-+#include <linux/root_dev.h>
-
- #include "mtdcore.h"
-
-@@ -637,6 +638,14 @@
- if (IS_ERR(slave))
- return PTR_ERR(slave);
-
-+ if (strcmp(parts[i].name, "rootfs") == 0) {
-+ if (ROOT_DEV == 0) {
-+ printk(KERN_NOTICE "mtd: partition \"rootfs\" "
-+ "set to be root filesystem\n");
-+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i);
-+ }
-+ }
-+
- mutex_lock(&mtd_partitions_mutex);
- list_add(&slave->list, &mtd_partitions);
- mutex_unlock(&mtd_partitions_mutex);
diff --git a/target/linux/patches/3.12.18/ppc64-missing-zlib.patch b/target/linux/patches/3.12.18/ppc64-missing-zlib.patch
deleted file mode 100644
index c6e0616be..000000000
--- a/target/linux/patches/3.12.18/ppc64-missing-zlib.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -Nur linux-3.11.5.orig/arch/powerpc/platforms/pseries/Kconfig linux-3.11.5/arch/powerpc/platforms/pseries/Kconfig
---- linux-3.11.5.orig/arch/powerpc/platforms/pseries/Kconfig 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/arch/powerpc/platforms/pseries/Kconfig 2013-11-01 15:23:09.000000000 +0100
-@@ -17,6 +17,7 @@
- select PPC_NATIVE
- select PPC_PCI_CHOICE if EXPERT
- select ZLIB_DEFLATE
-+ select ZLIB_INFLATE
- select PPC_DOORBELL
- select HAVE_CONTEXT_TRACKING
- select HOTPLUG_CPU if SMP
diff --git a/target/linux/patches/3.12.18/usb-defaults-off.patch b/target/linux/patches/3.12.18/usb-defaults-off.patch
deleted file mode 100644
index 54dff2bd4..000000000
--- a/target/linux/patches/3.12.18/usb-defaults-off.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff -Nur linux-3.5.orig//drivers/usb/host/Kconfig linux-3.5/drivers/usb/host/Kconfig
---- linux-3.5.orig//drivers/usb/host/Kconfig 2012-07-21 22:58:29.000000000 +0200
-+++ linux-3.5/drivers/usb/host/Kconfig 2012-07-29 11:59:56.000000000 +0200
-@@ -66,6 +66,7 @@
- config USB_EHCI_ROOT_HUB_TT
- bool "Root Hub Transaction Translators"
- depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
-+ default n
- ---help---
- Some EHCI chips have vendor-specific extensions to integrate
- transaction translators, so that no OHCI or UHCI companion
-@@ -78,7 +79,7 @@
- config USB_EHCI_TT_NEWSCHED
- bool "Improved Transaction Translator scheduling"
- depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
-- default y
-+ default n
- ---help---
- This changes the periodic scheduling code to fill more of the low
- and full speed bandwidth available from the Transaction Translator
diff --git a/target/linux/patches/3.12.18/vga-cons-default-off.patch b/target/linux/patches/3.12.18/vga-cons-default-off.patch
deleted file mode 100644
index 08a57f783..000000000
--- a/target/linux/patches/3.12.18/vga-cons-default-off.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Nur linux-3.11.5.orig/drivers/video/console/Kconfig linux-3.11.5/drivers/video/console/Kconfig
---- linux-3.11.5.orig/drivers/video/console/Kconfig 2013-10-14 03:14:45.000000000 +0200
-+++ linux-3.11.5/drivers/video/console/Kconfig 2013-10-16 18:04:45.000000000 +0200
-@@ -9,7 +9,7 @@
- depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \
- !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \
- (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
-- default y
-+ default n
- help
- Saying Y here will allow you to use Linux in text mode through a
- display that complies with the generic VGA standard. Virtually
diff --git a/target/linux/patches/3.11.10/bsd-compatibility.patch b/target/linux/patches/3.12.20/bsd-compatibility.patch
index b954b658f..b954b658f 100644
--- a/target/linux/patches/3.11.10/bsd-compatibility.patch
+++ b/target/linux/patches/3.12.20/bsd-compatibility.patch
diff --git a/target/linux/patches/3.11.10/defaults.patch b/target/linux/patches/3.12.20/defaults.patch
index 6cdca084e..6cdca084e 100644
--- a/target/linux/patches/3.11.10/defaults.patch
+++ b/target/linux/patches/3.12.20/defaults.patch
diff --git a/target/linux/patches/3.11.10/disable-netfilter.patch b/target/linux/patches/3.12.20/disable-netfilter.patch
index 7b1ca013a..7b1ca013a 100644
--- a/target/linux/patches/3.11.10/disable-netfilter.patch
+++ b/target/linux/patches/3.12.20/disable-netfilter.patch
diff --git a/target/linux/patches/3.11.10/export-symbol-for-exmap.patch b/target/linux/patches/3.12.20/export-symbol-for-exmap.patch
index 4f0fc8449..4f0fc8449 100644
--- a/target/linux/patches/3.11.10/export-symbol-for-exmap.patch
+++ b/target/linux/patches/3.12.20/export-symbol-for-exmap.patch
diff --git a/target/linux/patches/3.11.10/gemalto.patch b/target/linux/patches/3.12.20/gemalto.patch
index 65f7af1d7..65f7af1d7 100644
--- a/target/linux/patches/3.11.10/gemalto.patch
+++ b/target/linux/patches/3.12.20/gemalto.patch
diff --git a/target/linux/patches/3.11.10/lemote-rfkill.patch b/target/linux/patches/3.12.20/lemote-rfkill.patch
index a61488434..a61488434 100644
--- a/target/linux/patches/3.11.10/lemote-rfkill.patch
+++ b/target/linux/patches/3.12.20/lemote-rfkill.patch
diff --git a/target/linux/patches/3.11.10/microblaze-ethernet.patch b/target/linux/patches/3.12.20/microblaze-ethernet.patch
index 742ab477e..742ab477e 100644
--- a/target/linux/patches/3.11.10/microblaze-ethernet.patch
+++ b/target/linux/patches/3.12.20/microblaze-ethernet.patch
diff --git a/target/linux/patches/3.11.10/microblaze-setup.patch b/target/linux/patches/3.12.20/microblaze-setup.patch
index 43815f274..43815f274 100644
--- a/target/linux/patches/3.11.10/microblaze-setup.patch
+++ b/target/linux/patches/3.12.20/microblaze-setup.patch
diff --git a/target/linux/patches/3.11.10/mips-lzo-fix.patch b/target/linux/patches/3.12.20/mips-lzo-fix.patch
index 0740bdc6a..0740bdc6a 100644
--- a/target/linux/patches/3.11.10/mips-lzo-fix.patch
+++ b/target/linux/patches/3.12.20/mips-lzo-fix.patch
diff --git a/target/linux/patches/3.11.10/mtd-rootfs.patch b/target/linux/patches/3.12.20/mtd-rootfs.patch
index 775d5fc80..775d5fc80 100644
--- a/target/linux/patches/3.11.10/mtd-rootfs.patch
+++ b/target/linux/patches/3.12.20/mtd-rootfs.patch
diff --git a/target/linux/patches/3.11.10/non-static.patch b/target/linux/patches/3.12.20/non-static.patch
index a967703d0..a967703d0 100644
--- a/target/linux/patches/3.11.10/non-static.patch
+++ b/target/linux/patches/3.12.20/non-static.patch
diff --git a/target/linux/patches/3.11.10/ppc64-missing-zlib.patch b/target/linux/patches/3.12.20/ppc64-missing-zlib.patch
index c6e0616be..c6e0616be 100644
--- a/target/linux/patches/3.11.10/ppc64-missing-zlib.patch
+++ b/target/linux/patches/3.12.20/ppc64-missing-zlib.patch
diff --git a/target/linux/patches/3.12.18/startup.patch b/target/linux/patches/3.12.20/startup.patch
index 4cd477da1..4cd477da1 100644
--- a/target/linux/patches/3.12.18/startup.patch
+++ b/target/linux/patches/3.12.20/startup.patch
diff --git a/target/linux/patches/3.11.10/usb-defaults-off.patch b/target/linux/patches/3.12.20/usb-defaults-off.patch
index 54dff2bd4..54dff2bd4 100644
--- a/target/linux/patches/3.11.10/usb-defaults-off.patch
+++ b/target/linux/patches/3.12.20/usb-defaults-off.patch
diff --git a/target/linux/patches/3.11.10/uuid.patch b/target/linux/patches/3.12.20/uuid.patch
index ca23accdf..ca23accdf 100644
--- a/target/linux/patches/3.11.10/uuid.patch
+++ b/target/linux/patches/3.12.20/uuid.patch
diff --git a/target/linux/patches/3.11.10/vga-cons-default-off.patch b/target/linux/patches/3.12.20/vga-cons-default-off.patch
index 08a57f783..08a57f783 100644
--- a/target/linux/patches/3.11.10/vga-cons-default-off.patch
+++ b/target/linux/patches/3.12.20/vga-cons-default-off.patch
diff --git a/target/linux/patches/3.11.10/wlan-cf.patch b/target/linux/patches/3.12.20/wlan-cf.patch
index fc20759e2..fc20759e2 100644
--- a/target/linux/patches/3.11.10/wlan-cf.patch
+++ b/target/linux/patches/3.12.20/wlan-cf.patch
diff --git a/target/linux/patches/3.12.18/xargs.patch b/target/linux/patches/3.12.20/xargs.patch
index 2c7b3df59..2c7b3df59 100644
--- a/target/linux/patches/3.12.18/xargs.patch
+++ b/target/linux/patches/3.12.20/xargs.patch
diff --git a/target/linux/patches/3.12.20/yaffs2.patch b/target/linux/patches/3.12.20/yaffs2.patch
new file mode 100644
index 000000000..306814439
--- /dev/null
+++ b/target/linux/patches/3.12.20/yaffs2.patch
@@ -0,0 +1,16547 @@
+diff -Nur linux-3.12.20.orig/fs/Kconfig linux-3.12.20/fs/Kconfig
+--- linux-3.12.20.orig/fs/Kconfig 2014-05-15 09:56:19.000000000 +0200
++++ linux-3.12.20/fs/Kconfig 2014-05-17 11:28:49.000000000 +0200
+@@ -193,6 +193,7 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Nur linux-3.12.20.orig/fs/Makefile linux-3.12.20/fs/Makefile
+--- linux-3.12.20.orig/fs/Makefile 2014-05-15 09:56:19.000000000 +0200
++++ linux-3.12.20/fs/Makefile 2014-05-17 11:28:49.000000000 +0200
+@@ -126,3 +126,4 @@
+ obj-$(CONFIG_CEPH_FS) += ceph/
+ obj-$(CONFIG_PSTORE) += pstore/
+ obj-$(CONFIG_EFIVAR_FS) += efivarfs/
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
+diff -Nur linux-3.12.20.orig/fs/yaffs2/Kconfig linux-3.12.20/fs/yaffs2/Kconfig
+--- linux-3.12.20.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/Kconfig 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,171 @@
++#
++# yaffs file system configurations
++#
++
++config YAFFS_FS
++ tristate "yaffs2 file system support"
++ default n
++ depends on MTD_BLOCK
++ select YAFFS_YAFFS1
++ select YAFFS_YAFFS2
++ help
++ yaffs2, or Yet Another Flash File System, is a file 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
++ in yaffs_mtdif1.c.
++
++ 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_TAGS_ECC
++ bool "Disable yaffs from doing ECC on tags by default"
++ depends on YAFFS_FS && YAFFS_YAFFS2
++ default n
++ help
++ This defaults yaffs to using its own ECC calculations on tags instead of
++ just relying on the MTD.
++ This behavior can also be overridden with tags_ecc_on and
++ tags_ecc_off mount options.
++
++ 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_EMPTY_LOST_AND_FOUND
++ bool "Empty lost and found on boot"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is enabled then the contents of lost and found is
++ automatically dumped at mount.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++ bool "Disable yaffs2 block refreshing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then block refreshing is disabled.
++ Block refreshing infrequently refreshes the oldest block in
++ a yaffs2 file system. This mechanism helps to refresh flash to
++ mitigate against data loss. This is particularly useful for MLC.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++ bool "Disable yaffs2 background processing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then background processing is disabled.
++ Background processing makes many foreground activities faster.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BAD_BLOCK_MARKING
++ bool "Disable yaffs2 bad block marking"
++ depends on YAFFS_FS
++ default n
++ help
++ Useful during early flash bring up to prevent problems causing
++ lots of bad block marking.
++
++ If unsure, say N.
++
++config YAFFS_XATTR
++ bool "Enable yaffs2 xattr support"
++ depends on YAFFS_FS
++ default y
++ help
++ If this is set then yaffs2 will provide xattr support.
++ If unsure, say Y.
+diff -Nur linux-3.12.20.orig/fs/yaffs2/Makefile linux-3.12.20/fs/yaffs2/Makefile
+--- linux-3.12.20.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/Makefile 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,18 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
++yaffs-y += yaffs_mtdif.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_summary.o
++yaffs-y += yaffs_verify.o
++
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_allocator.c linux-3.12.20/fs/yaffs2/yaffs_allocator.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_allocator.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,357 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++/*
++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
++ * of approx 100 objects that are themn allocated singly.
++ * This is basically a simplified slab allocator.
++ *
++ * We don't use the Linux slab allocator because slab does not allow
++ * us to dump all the objects in one hit when we do a umount and tear
++ * down all the tnodes and objects. slab requires that we first free
++ * the individual objects.
++ *
++ * Once yaffs has been mainlined I shall try to motivate for a change
++ * to slab to provide the extra features we need here.
++ */
++
++struct yaffs_tnode_list {
++ struct yaffs_tnode_list *next;
++ struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++ struct yaffs_obj_list *next;
++ struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++ int n_tnodes_created;
++ struct yaffs_tnode *free_tnodes;
++ int n_free_tnodes;
++ struct yaffs_tnode_list *alloc_tnode_list;
++
++ int n_obj_created;
++ struct list_head free_objs;
++ int n_free_objects;
++
++ struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->alloc_tnode_list) {
++ tmp = allocator->alloc_tnode_list->next;
++
++ kfree(allocator->alloc_tnode_list->tnodes);
++ kfree(allocator->alloc_tnode_list);
++ allocator->alloc_tnode_list = tmp;
++ }
++
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->alloc_tnode_list = NULL;
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ int i;
++ struct yaffs_tnode *new_tnodes;
++ u8 *mem;
++ struct yaffs_tnode *curr;
++ struct yaffs_tnode *next;
++ struct yaffs_tnode_list *tnl;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_tnodes < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
++ mem = (u8 *) new_tnodes;
++
++ if (!new_tnodes) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: Could not allocate Tnodes");
++ return YAFFS_FAIL;
++ }
++
++ /* New hookup for wide tnodes */
++ for (i = 0; i < n_tnodes - 1; i++) {
++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++ curr->internal[0] = next;
++ }
++
++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++ curr->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++ allocator->n_free_tnodes += n_tnodes;
++ allocator->n_tnodes_created += n_tnodes;
++
++ /* Now add this bunch of tnodes to a list for freeing up.
++ * NB If we can't add this to the management list it isn't fatal
++ * but it just means we can't free this bunch of tnodes later.
++ */
++ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
++ if (!tnl) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Could not add tnodes to management list");
++ return YAFFS_FAIL;
++ } else {
++ tnl->tnodes = new_tnodes;
++ tnl->next = allocator->alloc_tnode_list;
++ allocator->alloc_tnode_list = tnl;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
++
++ return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode *tn = NULL;
++
++ if (!allocator) {
++ BUG();
++ return NULL;
++ }
++
++ /* If there are none left make more */
++ if (!allocator->free_tnodes)
++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++ if (allocator->free_tnodes) {
++ tn = allocator->free_tnodes;
++ allocator->free_tnodes = allocator->free_tnodes->internal[0];
++ allocator->n_free_tnodes--;
++ }
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ if (tn) {
++ tn->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = tn;
++ allocator->n_free_tnodes++;
++ }
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++/*--------------- yaffs_obj alloaction ------------------------
++ *
++ * Free yaffs_objs are stored in a list using obj->siblings.
++ * The blocks of allocated objects are stored in a linked list.
++ */
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->allocated_obj_list = NULL;
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ struct yaffs_obj_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->allocated_obj_list) {
++ tmp = allocator->allocated_obj_list->next;
++ kfree(allocator->allocated_obj_list->objects);
++ kfree(allocator->allocated_obj_list);
++ allocator->allocated_obj_list = tmp;
++ }
++
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++ allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ int i;
++ struct yaffs_obj *new_objs;
++ struct yaffs_obj_list *list;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_obj < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
++ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
++
++ if (!new_objs || !list) {
++ kfree(new_objs);
++ new_objs = NULL;
++ kfree(list);
++ list = NULL;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Could not allocate more objects");
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++ for (i = 0; i < n_obj; i++)
++ list_add(&new_objs[i].siblings, &allocator->free_objs);
++
++ allocator->n_free_objects += n_obj;
++ allocator->n_obj_created += n_obj;
++
++ /* Now add this bunch of Objects to a list for freeing up. */
++
++ list->objects = new_objs;
++ list->next = allocator->allocated_obj_list;
++ allocator->allocated_obj_list = list;
++
++ return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = NULL;
++ struct list_head *lh;
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return obj;
++ }
++
++ /* If there are none left make more */
++ if (list_empty(&allocator->free_objs))
++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++ if (!list_empty(&allocator->free_objs)) {
++ lh = allocator->free_objs.next;
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ list_del_init(lh);
++ allocator->n_free_objects--;
++ }
++
++ return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ /* Link into the free list. */
++ list_add(&obj->siblings, &allocator->free_objs);
++ allocator->n_free_objects++;
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++
++ if (!dev->allocator) {
++ BUG();
++ return;
++ }
++
++ yaffs_deinit_raw_tnodes(dev);
++ yaffs_deinit_raw_objs(dev);
++ kfree(dev->allocator);
++ dev->allocator = NULL;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator;
++
++ if (dev->allocator) {
++ BUG();
++ return;
++ }
++
++ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
++ if (allocator) {
++ dev->allocator = allocator;
++ yaffs_init_raw_tnodes(dev);
++ yaffs_init_raw_objs(dev);
++ }
++}
++
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_allocator.h linux-3.12.20/fs/yaffs2/yaffs_allocator.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_allocator.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_attribs.c linux-3.12.20/fs/yaffs2/yaffs_attribs.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_attribs.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return from_kuid(&init_user_ns, iattr->ia_uid);
++}
++
++static inline gid_t ia_gid_read(const struct iattr *iattr)
++{
++ return from_kgid(&init_user_ns, iattr->ia_gid);
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = make_kuid(&init_user_ns, uid);
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = make_kgid(&init_user_ns, gid);
++}
++#else
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return iattr->ia_uid;
++}
++
++static inline gid_t ia_gid_read(const struct iattr *inode)
++{
++ return iattr->ia_gid;
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = uid;
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = gid;
++}
++#endif
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++ obj->yst_uid = oh->yst_uid;
++ obj->yst_gid = oh->yst_gid;
++ obj->yst_atime = oh->yst_atime;
++ obj->yst_mtime = oh->yst_mtime;
++ obj->yst_ctime = oh->yst_ctime;
++ obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++ oh->yst_uid = obj->yst_uid;
++ oh->yst_gid = obj->yst_gid;
++ oh->yst_atime = obj->yst_atime;
++ oh->yst_mtime = obj->yst_mtime;
++ oh->yst_ctime = obj->yst_ctime;
++ oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++ obj->yst_mtime = Y_CURRENT_TIME;
++ if (do_a)
++ obj->yst_atime = obj->yst_mtime;
++ if (do_c)
++ obj->yst_ctime = obj->yst_mtime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++ yaffs_load_current_time(obj, 1, 1);
++ obj->yst_rdev = rdev;
++ obj->yst_uid = uid;
++ obj->yst_gid = gid;
++}
++
++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++ YCHAR *alias = NULL;
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return obj->variant.file_variant.file_size;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = obj->variant.symlink_variant.alias;
++ if (!alias)
++ return 0;
++ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++ default:
++ return 0;
++ }
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = attr->ia_valid;
++
++ if (valid & ATTR_MODE)
++ obj->yst_mode = attr->ia_mode;
++ if (valid & ATTR_UID)
++ obj->yst_uid = ia_uid_read(attr);
++ if (valid & ATTR_GID)
++ obj->yst_gid = ia_gid_read(attr);
++
++ if (valid & ATTR_ATIME)
++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++ if (valid & ATTR_CTIME)
++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++ if (valid & ATTR_MTIME)
++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++ if (valid & ATTR_SIZE)
++ yaffs_resize_file(obj, attr->ia_size);
++
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = 0;
++
++ attr->ia_mode = obj->yst_mode;
++ valid |= ATTR_MODE;
++ ia_uid_write(attr, obj->yst_uid);
++ valid |= ATTR_UID;
++ ia_gid_write(attr, obj->yst_gid);
++ valid |= ATTR_GID;
++
++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++ valid |= ATTR_ATIME;
++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++ valid |= ATTR_CTIME;
++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++ valid |= ATTR_MTIME;
++
++ attr->ia_size = yaffs_get_file_size(obj);
++ valid |= ATTR_SIZE;
++
++ attr->ia_valid = valid;
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_attribs.h linux-3.12.20/fs/yaffs2/yaffs_attribs.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_attribs.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_bitmap.c linux-3.12.20/fs/yaffs2/yaffs_bitmap.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_bitmap.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "BlockBits block %d is not valid",
++ blk);
++ BUG();
++ }
++ return dev->chunk_bits +
++ (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++ chunk < 0 || chunk >= dev->param.chunks_per_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Chunk Id (%d:%d) invalid",
++ blk, chunk);
++ BUG();
++ }
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++) {
++ if (*blk_bits)
++ return 1;
++ blk_bits++;
++ }
++ return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++ int n = 0;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
++ n += hweight8(*blk_bits);
++
++ return n;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_bitmap.h linux-3.12.20/fs/yaffs2/yaffs_bitmap.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_bitmap.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.12.20/fs/yaffs2/yaffs_checkptrw.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_checkptrw.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,474 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++struct yaffs_checkpt_chunk_hdr {
++ int version;
++ int seq;
++ u32 sum;
++ u32 xor;
++} ;
++
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++static int apply_block_offset(struct yaffs_dev *dev, int block)
++{
++ return block - dev->block_offset;
++}
++
++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ hdr.version = YAFFS_CHECKPOINT_VERSION;
++ hdr.seq = dev->checkpt_page_seq;
++ hdr.sum = dev->checkpt_sum;
++ hdr.xor = dev->checkpt_xor;
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
++}
++
++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ return hdr.version == YAFFS_CHECKPOINT_VERSION &&
++ hdr.seq == dev->checkpt_page_seq &&
++ hdr.sum == dev->checkpt_sum &&
++ hdr.xor == dev->checkpt_xor;
++}
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpt blocks_avail = %d", blocks_avail);
++
++ return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (!dev->drv.drv_erase_fn)
++ return 0;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checking blocks %d to %d",
++ dev->internal_start_block, dev->internal_end_block);
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ int offset_i = apply_block_offset(dev, i);
++ int result;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "erasing checkpt block %d", i);
++
++ dev->n_erasures++;
++
++ result = dev->drv.drv_erase_fn(dev, offset_i);
++ if(result) {
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ dev->n_free_chunks +=
++ dev->param.chunks_per_block;
++ } else {
++ dev->drv.drv_mark_bad_fn(dev, offset_i);
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ }
++ }
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++ int i;
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block: erased %d reserved %d avail %d next %d ",
++ dev->n_erased_blocks, dev->param.n_reserved_blocks,
++ blocks_avail, dev->checkpt_next_block);
++
++ if (dev->checkpt_next_block >= 0 &&
++ dev->checkpt_next_block <= dev->internal_end_block &&
++ blocks_avail > 0) {
++
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev, i);
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ dev->checkpt_next_block = i + 1;
++ dev->checkpt_cur_block = i;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block %d", i);
++ return;
++ }
++ }
++ }
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_ext_tags tags;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: start: blocks %d next %d",
++ dev->blocks_in_checkpt, dev->checkpt_next_block);
++
++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ int chunk = i * dev->param.chunks_per_block;
++ enum yaffs_block_state state;
++ u32 seq;
++
++ dev->tagger.read_chunk_tags_fn(dev,
++ apply_chunk_offset(dev, chunk),
++ NULL, &tags);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
++ i, (int) state,
++ tags.obj_id, tags.seq_number,
++ tags.ecc_result);
++
++ if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ continue;
++
++ dev->tagger.query_block_fn(dev,
++ apply_block_offset(dev, i),
++ &state, &seq);
++ if (state == YAFFS_BLOCK_STATE_DEAD)
++ continue;
++
++ /* Right kind of block */
++ dev->checkpt_next_block = tags.obj_id;
++ dev->checkpt_cur_block = i;
++ dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
++ dev->blocks_in_checkpt++;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "found checkpt block %d", i);
++ return;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++ int i;
++
++ dev->checkpt_open_write = writing;
++
++ /* Got the functions we need? */
++ if (!dev->tagger.write_chunk_tags_fn ||
++ !dev->tagger.read_chunk_tags_fn ||
++ !dev->drv.drv_erase_fn ||
++ !dev->drv.drv_mark_bad_fn)
++ return 0;
++
++ if (writing && !yaffs2_checkpt_space_ok(dev))
++ return 0;
++
++ if (!dev->checkpt_buffer)
++ dev->checkpt_buffer =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ dev->checkpt_page_seq = 0;
++ dev->checkpt_byte_count = 0;
++ dev->checkpt_sum = 0;
++ dev->checkpt_xor = 0;
++ dev->checkpt_cur_block = -1;
++ dev->checkpt_cur_chunk = -1;
++ dev->checkpt_next_block = dev->internal_start_block;
++
++ if (writing) {
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++ yaffs2_checkpt_init_chunk_hdr(dev);
++ return yaffs_checkpt_erase(dev);
++ }
++
++ /* Opening for a read */
++ /* Set to a value that will kick off a read */
++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++ /* A checkpoint block list of 1 checkpoint block per 16 block is
++ * (hopefully) going to be way more than we need */
++ dev->blocks_in_checkpt = 0;
++ dev->checkpt_max_blocks =
++ (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
++ dev->checkpt_block_list =
++ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
++
++ if (!dev->checkpt_block_list)
++ return 0;
++
++ for (i = 0; i < dev->checkpt_max_blocks; i++)
++ dev->checkpt_block_list[i] = -1;
++
++ return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++ u32 composite_sum;
++
++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
++ *sum = composite_sum;
++ return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++ int chunk;
++ int offset_chunk;
++ struct yaffs_ext_tags tags;
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_erased_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0)
++ return 0;
++
++ tags.is_deleted = 0;
++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
++ tags.chunk_id = dev->checkpt_page_seq + 1;
++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++ tags.n_bytes = dev->data_bytes_per_chunk;
++ if (dev->checkpt_cur_chunk == 0) {
++ /* First chunk we write for the block? Set block state to
++ checkpoint */
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, dev->checkpt_cur_block);
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ dev->blocks_in_checkpt++;
++ }
++
++ chunk =
++ dev->checkpt_cur_block * dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
++ tags.obj_id, tags.chunk_id);
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++
++ dev->n_page_writes++;
++
++ dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
++ dev->checkpt_buffer, &tags);
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++ dev->checkpt_cur_chunk = 0;
++ dev->checkpt_cur_block = -1;
++ }
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++ yaffs2_checkpt_init_chunk_hdr(dev);
++
++
++ return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (!dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++ ok = yaffs2_checkpt_flush_buffer(dev);
++ }
++
++ return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ struct yaffs_ext_tags tags;
++ int chunk;
++ int offset_chunk;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0) {
++ ok = 0;
++ break;
++ }
++
++ chunk = dev->checkpt_cur_block *
++ dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++ dev->n_page_reads++;
++
++ /* read in the next chunk */
++ dev->tagger.read_chunk_tags_fn(dev,
++ offset_chunk,
++ dev->checkpt_buffer,
++ &tags);
++
++ if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++ ok = 0;
++ break;
++ }
++ if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
++ ok = 0;
++ break;
++ }
++
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++
++ if (dev->checkpt_cur_chunk >=
++ dev->param.chunks_per_block)
++ dev->checkpt_cur_block = -1;
++
++ }
++
++ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++ }
++
++ return i;
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->checkpt_open_write) {
++ if (dev->checkpt_byte_offs !=
++ sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
++ yaffs2_checkpt_flush_buffer(dev);
++ } else if (dev->checkpt_block_list) {
++ for (i = 0;
++ i < dev->blocks_in_checkpt &&
++ dev->checkpt_block_list[i] >= 0; i++) {
++ int blk = dev->checkpt_block_list[i];
++ struct yaffs_block_info *bi = NULL;
++
++ if (dev->internal_start_block <= blk &&
++ blk <= dev->internal_end_block)
++ bi = yaffs_get_block_info(dev, blk);
++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ }
++ kfree(dev->checkpt_block_list);
++ dev->checkpt_block_list = NULL;
++ }
++
++ dev->n_free_chunks -=
++ dev->blocks_in_checkpt * dev->param.chunks_per_block;
++ dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
++ dev->checkpt_byte_count);
++
++ if (dev->checkpt_buffer) {
++ /* free the buffer */
++ kfree(dev->checkpt_buffer);
++ dev->checkpt_buffer = NULL;
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++ /* Erase the checkpoint data */
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint invalidate of %d blocks",
++ dev->blocks_in_checkpt);
++
++ return yaffs_checkpt_erase(dev);
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.12.20/fs/yaffs2/yaffs_checkptrw.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_checkptrw.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_ecc.c linux-3.12.20/fs/yaffs2/yaffs_ecc.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_ecc.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,281 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
++ * such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
++ * and therefore this bytes influence on the line parity.
++ */
++
++static const unsigned char column_parity_table[] = {
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned char line_parity = 0;
++ unsigned char line_parity_prime = 0;
++ unsigned char t;
++ unsigned char b;
++
++ for (i = 0; i < 256; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) { /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++ }
++
++ ecc[2] = (~col_parity) | 0x03;
++
++ t = 0;
++ if (line_parity & 0x80)
++ t |= 0x80;
++ if (line_parity_prime & 0x80)
++ t |= 0x40;
++ if (line_parity & 0x40)
++ t |= 0x20;
++ if (line_parity_prime & 0x40)
++ t |= 0x10;
++ if (line_parity & 0x20)
++ t |= 0x08;
++ if (line_parity_prime & 0x20)
++ t |= 0x04;
++ if (line_parity & 0x10)
++ t |= 0x02;
++ if (line_parity_prime & 0x10)
++ t |= 0x01;
++ ecc[1] = ~t;
++
++ t = 0;
++ if (line_parity & 0x08)
++ t |= 0x80;
++ if (line_parity_prime & 0x08)
++ t |= 0x40;
++ if (line_parity & 0x04)
++ t |= 0x20;
++ if (line_parity_prime & 0x04)
++ t |= 0x10;
++ if (line_parity & 0x02)
++ t |= 0x08;
++ if (line_parity_prime & 0x02)
++ t |= 0x04;
++ if (line_parity & 0x01)
++ t |= 0x02;
++ if (line_parity_prime & 0x01)
++ t |= 0x01;
++ ecc[0] = ~t;
++
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc)
++{
++ unsigned char d0, d1, d2; /* deltas */
++
++ d0 = read_ecc[0] ^ test_ecc[0];
++ d1 = read_ecc[1] ^ test_ecc[1];
++ d2 = read_ecc[2] ^ test_ecc[2];
++
++ if ((d0 | d1 | d2) == 0)
++ return 0; /* no error */
++
++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++ /* Single bit (recoverable) error in data */
++
++ unsigned byte;
++ unsigned bit;
++
++ bit = byte = 0;
++
++ if (d1 & 0x80)
++ byte |= 0x80;
++ if (d1 & 0x20)
++ byte |= 0x40;
++ if (d1 & 0x08)
++ byte |= 0x20;
++ if (d1 & 0x02)
++ byte |= 0x10;
++ if (d0 & 0x80)
++ byte |= 0x08;
++ if (d0 & 0x20)
++ byte |= 0x04;
++ if (d0 & 0x08)
++ byte |= 0x02;
++ if (d0 & 0x02)
++ byte |= 0x01;
++
++ if (d2 & 0x80)
++ bit |= 0x04;
++ if (d2 & 0x20)
++ bit |= 0x02;
++ if (d2 & 0x08)
++ bit |= 0x01;
++
++ data[byte] ^= (1 << bit);
++
++ return 1; /* Corrected the error */
++ }
++
++ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
++ /* Reccoverable error in ecc */
++
++ read_ecc[0] = test_ecc[0];
++ read_ecc[1] = test_ecc[1];
++ read_ecc[2] = test_ecc[2];
++
++ return 1; /* Corrected the error */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc_other)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned line_parity = 0;
++ unsigned line_parity_prime = 0;
++ unsigned char b;
++
++ for (i = 0; i < n_bytes; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) {
++ /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++
++ }
++
++ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++ ecc_other->line_parity = line_parity;
++ ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc)
++{
++ unsigned char delta_col; /* column parity delta */
++ unsigned delta_line; /* line parity delta */
++ unsigned delta_line_prime; /* line parity delta */
++ unsigned bit;
++
++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++ delta_line_prime =
++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++ if ((delta_col | delta_line | delta_line_prime) == 0)
++ return 0; /* no error */
++
++ if (delta_line == ~delta_line_prime &&
++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++ /* Single bit (recoverable) error in data */
++
++ bit = 0;
++
++ if (delta_col & 0x20)
++ bit |= 0x04;
++ if (delta_col & 0x08)
++ bit |= 0x02;
++ if (delta_col & 0x02)
++ bit |= 0x01;
++
++ if (delta_line >= n_bytes)
++ return -1;
++
++ data[delta_line] ^= (1 << bit);
++
++ return 1; /* corrected */
++ }
++
++ if ((hweight32(delta_line) +
++ hweight32(delta_line_prime) +
++ hweight8(delta_col)) == 1) {
++ /* Reccoverable error in ecc */
++
++ *read_ecc = *test_ecc;
++ return 1; /* corrected */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_ecc.h linux-3.12.20/fs/yaffs2/yaffs_ecc.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_ecc.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data.
++ * Thus, two such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++ unsigned char col_parity;
++ unsigned line_parity;
++ unsigned line_parity_prime;
++};
++
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc);
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.12.20/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_getblockinfo.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++ *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs: get_block_info block %d is not valid",
++ blk);
++ BUG();
++ }
++ return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_guts.c linux-3.12.20/fs/yaffs2/yaffs_guts.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_guts.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,5146 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsmarshall.h"
++#include "yaffs_nand.h"
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Forward declarations */
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve);
++
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size);
++
++/* Function to calculate chunk and offset */
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out)
++{
++ int chunk;
++ u32 offset;
++
++ chunk = (u32) (addr >> dev->chunk_shift);
++
++ if (dev->chunk_div == 1) {
++ /* easy power of 2 case */
++ offset = (u32) (addr & dev->chunk_mask);
++ } else {
++ /* Non power-of-2 case */
++
++ loff_t chunk_base;
++
++ chunk /= dev->chunk_div;
++
++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++ offset = (u32) (addr - chunk_base);
++ }
++
++ *chunk_out = chunk;
++ *offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static inline u32 calc_shifts_ceiling(u32 x)
++{
++ int extra_bits;
++ int shifts;
++
++ shifts = extra_bits = 0;
++
++ while (x > 1) {
++ if (x & 1)
++ extra_bits++;
++ x >>= 1;
++ shifts++;
++ }
++
++ if (extra_bits)
++ shifts++;
++
++ return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static inline u32 calc_shifts(u32 x)
++{
++ u32 shifts;
++
++ shifts = 0;
++
++ if (!x)
++ return 0;
++
++ while (!(x & 1)) {
++ x >>= 1;
++ shifts++;
++ }
++
++ return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++ int i;
++ u8 *buf = (u8 *) 1;
++
++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++ dev->temp_buffer[i].in_use = 0;
++ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ dev->temp_buffer[i].buffer = buf;
++ }
++
++ return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
++{
++ int i;
++
++ dev->temp_in_use++;
++ if (dev->temp_in_use > dev->max_temp)
++ dev->max_temp = dev->temp_in_use;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].in_use == 0) {
++ dev->temp_buffer[i].in_use = 1;
++ return dev->temp_buffer[i].buffer;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
++ /*
++ * If we got here then we have to allocate an unmanaged one
++ * This is not good.
++ */
++
++ dev->unmanaged_buffer_allocs++;
++ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
++{
++ int i;
++
++ dev->temp_in_use--;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].buffer == buffer) {
++ dev->temp_buffer[i].in_use = 0;
++ return;
++ }
++ }
++
++ if (buffer) {
++ /* assume it is an unmanaged one. */
++ yaffs_trace(YAFFS_TRACE_BUFFERS,
++ "Releasing unmanaged temp buffer");
++ kfree(buffer);
++ dev->unmanaged_buffer_deallocs++;
++ }
++
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) data;
++ (void) tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++ if (!bi->gc_prioritise) {
++ bi->gc_prioritise = 1;
++ dev->has_pending_prioritised_gc = 1;
++ bi->chunk_error_strikes++;
++
++ if (bi->chunk_error_strikes > 3) {
++ bi->needs_retiring = 1; /* Too many stikes, so retire */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Block struck out");
++
++ }
++ }
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++ int erased_ok)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs_handle_chunk_error(dev, bi);
++
++ if (erased_ok) {
++ /* Was an actual write failure,
++ * so mark the block for retirement.*/
++ bi->needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d needs retiring", flash_block);
++ }
++
++ /* Delete the chunk */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ * Simple hash function. Needs to have a reasonable spread
++ */
++
++static inline int yaffs_hash_fn(int n)
++{
++ if (n < 0)
++ n = -n;
++ return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++ return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++ return dev->lost_n_found;
++}
++
++/*
++ * Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 *buffer, int n_bytes)
++{
++ /* Horrible, slow implementation */
++ while (n_bytes--) {
++ if (*buffer != 0xff)
++ return 0;
++ buffer++;
++ }
++ return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++ int retval = YAFFS_OK;
++ u8 *data = yaffs_get_temp_buffer(dev);
++ struct yaffs_ext_tags tags;
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++ retval = YAFFS_FAIL;
++
++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
++ tags.chunk_used) {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not erased", nand_chunk);
++ retval = YAFFS_FAIL;
++ }
++
++ yaffs_release_temp_buffer(dev, data);
++
++ return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = YAFFS_OK;
++ struct yaffs_ext_tags temp_tags;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++ temp_tags.obj_id != tags->obj_id ||
++ temp_tags.chunk_id != tags->chunk_id ||
++ temp_tags.n_bytes != tags->n_bytes)
++ retval = YAFFS_FAIL;
++
++ yaffs_release_temp_buffer(dev, buffer);
++
++ return retval;
++}
++
++
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
++{
++ int reserved_chunks;
++ int reserved_blocks = dev->param.n_reserved_blocks;
++ int checkpt_blocks;
++
++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
++
++ reserved_chunks =
++ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
++
++ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
++}
++
++static int yaffs_find_alloc_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_block_info *bi;
++
++ if (dev->n_erased_blocks < 1) {
++ /* Hoosterman we've got a problem.
++ * Can't get space to gc
++ */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no more erased blocks");
++
++ return -1;
++ }
++
++ /* Find an empty block. */
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ dev->alloc_block_finder++;
++ if (dev->alloc_block_finder < dev->internal_start_block
++ || dev->alloc_block_finder > dev->internal_end_block) {
++ dev->alloc_block_finder = dev->internal_start_block;
++ }
++
++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->seq_number++;
++ bi->seq_number = dev->seq_number;
++ dev->n_erased_blocks--;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Allocated block %d, seq %d, %d left" ,
++ dev->alloc_block_finder, dev->seq_number,
++ dev->n_erased_blocks);
++ return dev->alloc_block_finder;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs tragedy: no more erased blocks, but there should have been %d",
++ dev->n_erased_blocks);
++
++ return -1;
++}
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++ struct yaffs_block_info **block_ptr)
++{
++ int ret_val;
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block < 0) {
++ /* Get next block to allocate off */
++ dev->alloc_block = yaffs_find_alloc_block(dev);
++ dev->alloc_page = 0;
++ }
++
++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
++ /* No space unless we're allowed to use the reserve. */
++ return -1;
++ }
++
++ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
++ && dev->alloc_page == 0)
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
++
++ /* Next page please.... */
++ if (dev->alloc_block >= 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++
++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
++ dev->alloc_page;
++ bi->pages_in_use++;
++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
++
++ dev->alloc_page++;
++
++ dev->n_free_chunks--;
++
++ /* If the block is full set the state to full */
++ if (dev->alloc_page >= dev->param.chunks_per_block) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ if (block_ptr)
++ *block_ptr = bi;
++
++ return ret_val;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
++
++ return -1;
++}
++
++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
++{
++ int n;
++
++ n = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ if (dev->alloc_block > 0)
++ n += (dev->param.chunks_per_block - dev->alloc_page);
++
++ return n;
++
++}
++
++/*
++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
++{
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block > 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++ }
++}
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++ const u8 *data,
++ struct yaffs_ext_tags *tags, int use_reserver)
++{
++ int attempts = 0;
++ int write_ok = 0;
++ int chunk;
++
++ yaffs2_checkpt_invalidate(dev);
++
++ do {
++ struct yaffs_block_info *bi = 0;
++ int erased_ok = 0;
++
++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
++ if (chunk < 0) {
++ /* no space */
++ break;
++ }
++
++ /* First check this chunk is erased, if it needs
++ * checking. The checking policy (unless forced
++ * always on) is as follows:
++ *
++ * Check the first page we try to write in a block.
++ * If the check passes then we don't need to check any
++ * more. If the check fails, we check again...
++ * If the block has been erased, we don't need to check.
++ *
++ * However, if the block has been prioritised for gc,
++ * then we think there might be something odd about
++ * this block and stop using it.
++ *
++ * Rationale: We should only ever see chunks that have
++ * not been erased if there was a partially written
++ * chunk due to power loss. This checking policy should
++ * catch that case with very few checks and thus save a
++ * lot of checks that are most likely not needed.
++ *
++ * Mods to the above
++ * If an erase check fails or the write fails we skip the
++ * rest of the block.
++ */
++
++ /* let's give it a try */
++ attempts++;
++
++ if (dev->param.always_check_erased)
++ bi->skip_erased_check = 0;
++
++ if (!bi->skip_erased_check) {
++ erased_ok = yaffs_check_chunk_erased(dev, chunk);
++ if (erased_ok != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs chunk %d was not erased",
++ chunk);
++
++ /* If not erased, delete this one,
++ * skip rest of block and
++ * try another chunk */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++ continue;
++ }
++ }
++
++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
++
++ if (!bi->skip_erased_check)
++ write_ok =
++ yaffs_verify_chunk_written(dev, chunk, data, tags);
++
++ if (write_ok != YAFFS_OK) {
++ /* Clean up aborted write, skip to next block and
++ * try another chunk */
++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
++ continue;
++ }
++
++ bi->skip_erased_check = 1;
++
++ /* Copy the data into the robustification buffer */
++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
++
++ } while (write_ok != YAFFS_OK &&
++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++ if (!write_ok)
++ chunk = -1;
++
++ if (attempts > 1) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs write required %d attempts",
++ attempts);
++ dev->n_retried_writes += (attempts - 1);
++ }
++
++ return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to mark bad and erase block %d",
++ flash_block);
++ } else {
++ struct yaffs_ext_tags tags;
++ int chunk_id =
++ flash_block * dev->param.chunks_per_block;
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ memset(&tags, 0, sizeof(tags));
++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
++ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
++ dev->chunk_offset,
++ buffer,
++ &tags) != YAFFS_OK)
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to write bad block marker to block %d",
++ flash_block);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++ }
++
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ bi->gc_prioritise = 0;
++ bi->needs_retiring = 0;
++
++ dev->n_retired_blocks++;
++}
++
++/*---------------- Name handling functions ------------*/
++
++static u16 yaffs_calc_name_sum(const YCHAR *name)
++{
++ u16 sum = 0;
++ u16 i = 1;
++
++ if (!name)
++ return 0;
++
++ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
++
++ /* 0x1f mask is case insensitive */
++ sum += ((*name) & 0x1f) * i;
++ i++;
++ name++;
++ }
++ return sum;
++}
++
++
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
++{
++ memset(obj->short_name, 0, sizeof(obj->short_name));
++
++ if (name && !name[0]) {
++ yaffs_fix_null_name(obj, obj->short_name,
++ YAFFS_SHORT_NAME_LENGTH);
++ name = obj->short_name;
++ } else if (name &&
++ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
++ YAFFS_SHORT_NAME_LENGTH) {
++ strcpy(obj->short_name, name);
++ }
++
++ obj->sum = yaffs_calc_name_sum(name);
++}
++
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
++ memset(tmp_name, 0, sizeof(tmp_name));
++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_set_obj_name(obj, tmp_name);
++#else
++ yaffs_set_obj_name(obj, oh->name);
++#endif
++}
++
++loff_t yaffs_max_file_size(struct yaffs_dev *dev)
++{
++ if(sizeof(loff_t) < 8)
++ return YAFFS_MAX_FILE_SIZE_32;
++ else
++ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
++
++ if (tn) {
++ memset(tn, 0, dev->tnode_size);
++ dev->n_tnodes++;
++ }
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ yaffs_free_raw_tnode(dev, tn);
++ dev->n_tnodes--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ yaffs_deinit_raw_tnodes_and_objs(dev);
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++}
++
++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos, unsigned val)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 mask;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++ val >>= dev->chunk_grp_bits;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ mask = dev->tnode_mask << bit_in_word;
++
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val << bit_in_word));
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ mask =
++ dev->tnode_mask >> bit_in_word;
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val >> bit_in_word));
++ }
++}
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 val;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ val = map[word_in_map] >> bit_in_word;
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ val |= (map[word_in_map] << bit_in_word);
++ }
++
++ val &= dev->tnode_mask;
++ val <<= dev->chunk_grp_bits;
++
++ return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of top_level
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id)
++{
++ struct yaffs_tnode *tn = file_struct->top;
++ u32 i;
++ int required_depth;
++ int level = file_struct->top_level;
++
++ (void) dev;
++
++ /* Check sane level and chunk Id */
++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (i) {
++ i >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level)
++ return NULL; /* Not tall enough, so we can't find it */
++
++ /* Traverse down to level 0 */
++ while (level > 0 && tn) {
++ tn = tn->internal[(chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (level - 1) *
++ YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK];
++ level--;
++ }
++
++ return tn;
++}
++
++/* add_find_tnode_0 finds the level 0 tnode if it exists,
++ * otherwise first expands the tree.
++ * This happens in two steps:
++ * 1. If the tree isn't tall enough, then make it taller.
++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the
++ * specified tn will be plugged into the ttree.
++ */
++
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn)
++{
++ int required_depth;
++ int i;
++ int l;
++ struct yaffs_tnode *tn;
++ u32 x;
++
++ /* Check sane level and page Id */
++ if (file_struct->top_level < 0 ||
++ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level) {
++ /* Not tall enough, gotta make the tree taller */
++ for (i = file_struct->top_level; i < required_depth; i++) {
++
++ tn = yaffs_get_tnode(dev);
++
++ if (tn) {
++ tn->internal[0] = file_struct->top;
++ file_struct->top = tn;
++ file_struct->top_level++;
++ } else {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: no more tnodes");
++ return NULL;
++ }
++ }
++ }
++
++ /* Traverse down to level 0, adding anything we need */
++
++ l = file_struct->top_level;
++ tn = file_struct->top;
++
++ if (l > 0) {
++ while (l > 0 && tn) {
++ x = (chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK;
++
++ if ((l > 1) && !tn->internal[x]) {
++ /* Add missing non-level-zero tnode */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ } else if (l == 1) {
++ /* Looking from level 1 at level 0 */
++ if (passed_tn) {
++ /* If we already have one, release it */
++ if (tn->internal[x])
++ yaffs_free_tnode(dev,
++ tn->internal[x]);
++ tn->internal[x] = passed_tn;
++
++ } else if (!tn->internal[x]) {
++ /* Don't have one, none passed in */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ }
++ }
++
++ tn = tn->internal[x];
++ l--;
++ }
++ } else {
++ /* top is level 0 */
++ if (passed_tn) {
++ memcpy(tn, passed_tn,
++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
++ yaffs_free_tnode(dev, passed_tn);
++ }
++ }
++
++ return tn;
++}
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++ int chunk_obj)
++{
++ return (tags->chunk_id == chunk_obj &&
++ tags->obj_id == obj_id &&
++ !tags->is_deleted) ? 1 : 0;
++
++}
++
++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
++ struct yaffs_ext_tags *tags, int obj_id,
++ int inode_chunk)
++{
++ int j;
++
++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
++ if (yaffs_check_chunk_bit
++ (dev, the_chunk / dev->param.chunks_per_block,
++ the_chunk % dev->param.chunks_per_block)) {
++
++ if (dev->chunk_grp_size == 1)
++ return the_chunk;
++ else {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ tags);
++ if (yaffs_tags_match(tags,
++ obj_id, inode_chunk)) {
++ /* found it; */
++ return the_chunk;
++ }
++ }
++ }
++ the_chunk++;
++ }
++ return -1;
++}
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /*Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ int ret_val = -1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++ return ret_val;
++}
++
++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /* Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ struct yaffs_dev *dev = in->my_dev;
++ int ret_val = -1;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++
++ /* Delete the entry in the filestructure (if found) */
++ if (ret_val != -1)
++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
++
++ return ret_val;
++}
++
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan)
++{
++ /* NB in_scan is zero unless scanning.
++ * For forward scanning, in_scan is > 0;
++ * for backward scanning in_scan is < 0
++ *
++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
++ */
++
++ struct yaffs_tnode *tn;
++ struct yaffs_dev *dev = in->my_dev;
++ int existing_cunk;
++ struct yaffs_ext_tags existing_tags;
++ struct yaffs_ext_tags new_tags;
++ unsigned existing_serial, new_serial;
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
++ /* Just ignore an attempt at putting a chunk into a non-file
++ * during scanning.
++ * If it is not during Scanning then something went wrong!
++ */
++ if (!in_scan) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy:attempt to put data chunk into a non-file"
++ );
++ BUG();
++ }
++
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++
++ tn = yaffs_add_find_tnode_0(dev,
++ &in->variant.file_variant,
++ inode_chunk, NULL);
++ if (!tn)
++ return YAFFS_FAIL;
++
++ if (!nand_chunk)
++ /* Dummy insert, bail now */
++ return YAFFS_OK;
++
++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ if (in_scan != 0) {
++ /* If we're scanning then we need to test for duplicates
++ * NB This does not need to be efficient since it should only
++ * happen when the power fails during a write, then only one
++ * chunk should ever be affected.
++ *
++ * Correction for YAFFS2: This could happen quite a lot and we
++ * need to think about efficiency! TODO
++ * Update: For backward scanning we don't need to re-read tags
++ * so this is quite cheap.
++ */
++
++ if (existing_cunk > 0) {
++ /* NB Right now existing chunk will not be real
++ * chunk_id if the chunk group size > 1
++ * thus we have to do a FindChunkInFile to get the
++ * real chunk id.
++ *
++ * We have a duplicate now we need to decide which
++ * one to use:
++ *
++ * Backwards scanning YAFFS2: The old one is what
++ * we use, dump the new one.
++ * YAFFS1: Get both sets of tags and compare serial
++ * numbers.
++ */
++
++ if (in_scan > 0) {
++ /* Only do this for forward scanning */
++ yaffs_rd_chunk_tags_nand(dev,
++ nand_chunk,
++ NULL, &new_tags);
++
++ /* Do a proper find */
++ existing_cunk =
++ yaffs_find_chunk_in_file(in, inode_chunk,
++ &existing_tags);
++ }
++
++ if (existing_cunk <= 0) {
++ /*Hoosterman - how did this happen? */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: existing chunk < 0 in scan"
++ );
++
++ }
++
++ /* NB The deleted flags should be false, otherwise
++ * the chunks will not be loaded during a scan
++ */
++
++ if (in_scan > 0) {
++ new_serial = new_tags.serial_number;
++ existing_serial = existing_tags.serial_number;
++ }
++
++ if ((in_scan > 0) &&
++ (existing_cunk <= 0 ||
++ ((existing_serial + 1) & 3) == new_serial)) {
++ /* Forward scanning.
++ * Use new
++ * Delete the old one and drop through to
++ * update the tnode
++ */
++ yaffs_chunk_del(dev, existing_cunk, 1,
++ __LINE__);
++ } else {
++ /* Backward scanning or we want to use the
++ * existing one
++ * Delete the new one and return early so that
++ * the tnode isn't changed
++ */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++ }
++
++ }
++
++ if (existing_cunk == 0)
++ in->n_data_chunks++;
++
++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
++
++ return YAFFS_OK;
++}
++
++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
++{
++ struct yaffs_block_info *the_block;
++ unsigned block_no;
++
++ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
++
++ block_no = chunk / dev->param.chunks_per_block;
++ the_block = yaffs_get_block_info(dev, block_no);
++ if (the_block) {
++ the_block->soft_del_pages++;
++ dev->n_free_chunks++;
++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
++ }
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
++ * the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls
++ * the chunk out of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks
++ * are soft deleted.
++ */
++
++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
++ u32 level, int chunk_offset)
++{
++ int i;
++ int the_chunk;
++ int all_done = 1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = YAFFS_NTNODES_INTERNAL - 1;
++ all_done && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ all_done =
++ yaffs_soft_del_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ if (all_done) {
++ yaffs_free_tnode(dev,
++ tn->internal[i]);
++ tn->internal[i] = NULL;
++ } else {
++ /* Can this happen? */
++ }
++ }
++ }
++ return (all_done) ? 1 : 0;
++ }
++
++ /* level 0 */
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk) {
++ yaffs_soft_del_chunk(dev, the_chunk);
++ yaffs_load_tnode_0(dev, tn, i, 0);
++ }
++ }
++ return 1;
++}
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_obj *parent;
++
++ yaffs_verify_obj_in_dir(obj);
++ parent = obj->parent;
++
++ yaffs_verify_dir(parent);
++
++ if (dev && dev->param.remove_obj_fn)
++ dev->param.remove_obj_fn(obj);
++
++ list_del_init(&obj->siblings);
++ obj->parent = NULL;
++
++ yaffs_verify_dir(parent);
++}
++
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
++{
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a null pointer directory"
++ );
++ BUG();
++ return;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a non-directory"
++ );
++ BUG();
++ }
++
++ if (obj->siblings.prev == NULL) {
++ /* Not initialised */
++ BUG();
++ }
++
++ yaffs_verify_dir(directory);
++
++ yaffs_remove_obj_from_dir(obj);
++
++ /* Now add it */
++ list_add(&obj->siblings, &directory->variant.dir_variant.children);
++ obj->parent = directory;
++
++ if (directory == obj->my_dev->unlinked_dir
++ || directory == obj->my_dev->del_dir) {
++ obj->unlinked = 1;
++ obj->my_dev->n_unlinked_files++;
++ obj->rename_allowed = 0;
++ }
++
++ yaffs_verify_dir(directory);
++ yaffs_verify_obj_in_dir(obj);
++}
++
++static int yaffs_change_obj_name(struct yaffs_obj *obj,
++ struct yaffs_obj *new_dir,
++ const YCHAR *new_name, int force, int shadows)
++{
++ int unlink_op;
++ int del_op;
++ struct yaffs_obj *existing_target;
++
++ if (new_dir == NULL)
++ new_dir = obj->parent; /* use the old directory */
++
++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_change_obj_name: new_dir is not a directory"
++ );
++ BUG();
++ }
++
++ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
++ del_op = (new_dir == obj->my_dev->del_dir);
++
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++
++ /* If the object is a file going into the unlinked directory,
++ * then it is OK to just stuff it in since duplicate names are OK.
++ * else only proceed if the new name does not exist and we're putting
++ * it into a directory.
++ */
++ if (!(unlink_op || del_op || force ||
++ shadows > 0 || !existing_target) ||
++ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ return YAFFS_FAIL;
++
++ yaffs_set_obj_name(obj, new_name);
++ obj->dirty = 1;
++ yaffs_add_obj_to_dir(new_dir, obj);
++
++ if (unlink_op)
++ obj->unlinked = 1;
++
++ /* If it is a deletion then we mark it as a shrink for gc */
++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++/*------------------------ Short Operations Cache ------------------------------
++ * In many situations where there is no high level buffering a lot of
++ * reads might be short sequential reads, and a lot of writes may be short
++ * sequential writes. eg. scanning/writing a jpeg file.
++ * In these cases, a short read/write cache can provide a huge perfomance
++ * benefit with dumb-as-a-rock code.
++ * In Linux, the page cache provides read buffering and the short op cache
++ * provides write buffering.
++ *
++ * There are a small number (~10) of cache chunks per device so that we don't
++ * need a very intelligent search.
++ */
++
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++ struct yaffs_cache *cache;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ for (i = 0; i < n_caches; i++) {
++ cache = &dev->cache[i];
++ if (cache->object == obj && cache->dirty)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void yaffs_flush_file_cache(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int lowest = -99; /* Stop compiler whining. */
++ int i;
++ struct yaffs_cache *cache;
++ int chunk_written = 0;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ if (n_caches < 1)
++ return;
++ do {
++ cache = NULL;
++
++ /* Find the lowest dirty chunk for this object */
++ for (i = 0; i < n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].dirty) {
++ if (!cache ||
++ dev->cache[i].chunk_id < lowest) {
++ cache = &dev->cache[i];
++ lowest = cache->chunk_id;
++ }
++ }
++ }
++
++ if (cache && !cache->locked) {
++ /* Write it out and free it up */
++ chunk_written =
++ yaffs_wr_data_obj(cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ cache->object = NULL;
++ }
++ } while (cache && chunk_written > 0);
++
++ if (cache)
++ /* Hoosterman, disk full while writing cache out. */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no space during cache write");
++}
++
++/*yaffs_flush_whole_cache(dev)
++ *
++ *
++ */
++
++void yaffs_flush_whole_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int n_caches = dev->param.n_caches;
++ int i;
++
++ /* Find a dirty object in the cache and flush it...
++ * until there are no further dirty objects.
++ */
++ do {
++ obj = NULL;
++ for (i = 0; i < n_caches && !obj; i++) {
++ if (dev->cache[i].object && dev->cache[i].dirty)
++ obj = dev->cache[i].object;
++ }
++ if (obj)
++ yaffs_flush_file_cache(obj);
++ } while (obj);
++
++}
++
++/* Grab us a cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->param.n_caches > 0) {
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (!dev->cache[i].object)
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_cache *cache;
++ struct yaffs_obj *the_obj;
++ int usage;
++ int i;
++ int pushout;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ /* Try find a non-dirty one... */
++
++ cache = yaffs_grab_chunk_worker(dev);
++
++ if (!cache) {
++ /* They were all dirty, find the LRU object and flush
++ * its cache, then find again.
++ * NB what's here is not very accurate,
++ * we actually flush the object with the LRU chunk.
++ */
++
++ /* With locking we can't assume we can use entry zero,
++ * Set the_obj to a valid pointer for Coverity. */
++ the_obj = dev->cache[0].object;
++ usage = -1;
++ cache = NULL;
++ pushout = -1;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object &&
++ !dev->cache[i].locked &&
++ (dev->cache[i].last_use < usage ||
++ !cache)) {
++ usage = dev->cache[i].last_use;
++ the_obj = dev->cache[i].object;
++ cache = &dev->cache[i];
++ pushout = i;
++ }
++ }
++
++ if (!cache || cache->dirty) {
++ /* Flush and try again */
++ yaffs_flush_file_cache(the_obj);
++ cache = yaffs_grab_chunk_worker(dev);
++ }
++ }
++ return cache;
++}
++
++/* Find a cached chunk */
++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
++ int chunk_id)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].chunk_id == chunk_id) {
++ dev->cache_hits++;
++
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
++ int is_write)
++{
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return;
++
++ if (dev->cache_last_use < 0 ||
++ dev->cache_last_use > 100000000) {
++ /* Reset the cache usages */
++ for (i = 1; i < dev->param.n_caches; i++)
++ dev->cache[i].last_use = 0;
++
++ dev->cache_last_use = 0;
++ }
++ dev->cache_last_use++;
++ cache->last_use = dev->cache_last_use;
++
++ if (is_write)
++ cache->dirty = 1;
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
++{
++ struct yaffs_cache *cache;
++
++ if (object->my_dev->param.n_caches > 0) {
++ cache = yaffs_find_chunk_cache(object, chunk_id);
++
++ if (cache)
++ cache->object = NULL;
++ }
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.n_caches > 0) {
++ /* Invalidate it. */
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == in)
++ dev->cache[i].object = NULL;
++ }
++ }
++}
++
++static void yaffs_unhash_obj(struct yaffs_obj *obj)
++{
++ int bucket;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ /* If it is still linked into the bucket list, free from the list */
++ if (!list_empty(&obj->hash_link)) {
++ list_del_init(&obj->hash_link);
++ bucket = yaffs_hash_fn(obj->obj_id);
++ dev->obj_bucket[bucket].count--;
++ }
++}
++
++/* FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_free_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj) {
++ BUG();
++ return;
++ }
++ dev = obj->my_dev;
++ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
++ obj, obj->my_inode);
++ if (obj->parent)
++ BUG();
++ if (!list_empty(&obj->siblings))
++ BUG();
++
++ if (obj->my_inode) {
++ /* We're still hooked up to a cached inode.
++ * Don't delete now, but mark for later deletion
++ */
++ obj->defered_free = 1;
++ return;
++ }
++
++ yaffs_unhash_obj(obj);
++
++ yaffs_free_raw_obj(dev, obj);
++ dev->n_obj--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj)
++{
++ if (obj->defered_free)
++ yaffs_free_obj(obj);
++}
++
++static int yaffs_generic_obj_del(struct yaffs_obj *in)
++{
++ /* Iinvalidate the file's data in the cache, without flushing. */
++ yaffs_invalidate_whole_cache(in);
++
++ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
++ /* Move to unlinked directory so we have a deletion record */
++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
++ 0);
++ }
++
++ yaffs_remove_obj_from_dir(in);
++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
++ in->hdr_chunk = 0;
++
++ yaffs_free_obj(in);
++ return YAFFS_OK;
++
++}
++
++static void yaffs_soft_del_file(struct yaffs_obj *obj)
++{
++ if (!obj->deleted ||
++ obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
++ obj->soft_del)
++ return;
++
++ if (obj->n_data_chunks <= 0) {
++ /* Empty file with no duplicate object headers,
++ * just delete it immediately */
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: Deleting empty file %d",
++ obj->obj_id);
++ yaffs_generic_obj_del(obj);
++ } else {
++ yaffs_soft_del_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.
++ file_variant.top_level, 0);
++ obj->soft_del = 1;
++ }
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
++ struct yaffs_tnode *tn, u32 level,
++ int del0)
++{
++ int i;
++ int has_data;
++
++ if (!tn)
++ return tn;
++
++ has_data = 0;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i]) {
++ tn->internal[i] =
++ yaffs_prune_worker(dev,
++ tn->internal[i],
++ level - 1,
++ (i == 0) ? del0 : 1);
++ }
++
++ if (tn->internal[i])
++ has_data++;
++ }
++ } else {
++ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
++ u32 *map = (u32 *) tn;
++
++ for (i = 0; !has_data && i < tnode_size_u32; i++) {
++ if (map[i])
++ has_data++;
++ }
++ }
++
++ if (has_data == 0 && del0) {
++ /* Free and return NULL */
++ yaffs_free_tnode(dev, tn);
++ tn = NULL;
++ }
++ return tn;
++}
++
++static int yaffs_prune_tree(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct)
++{
++ int i;
++ int has_data;
++ int done = 0;
++ struct yaffs_tnode *tn;
++
++ if (file_struct->top_level < 1)
++ return YAFFS_OK;
++
++ file_struct->top =
++ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
++
++ /* Now we have a tree with all the non-zero branches NULL but
++ * the height is the same as it was.
++ * Let's see if we can trim internal tnodes to shorten the tree.
++ * We can do this if only the 0th element in the tnode is in use
++ * (ie all the non-zero are NULL)
++ */
++
++ while (file_struct->top_level && !done) {
++ tn = file_struct->top;
++
++ has_data = 0;
++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i])
++ has_data++;
++ }
++
++ if (!has_data) {
++ file_struct->top = tn->internal[0];
++ file_struct->top_level--;
++ yaffs_free_tnode(dev, tn);
++ } else {
++ done = 1;
++ }
++ }
++
++ return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* alloc_empty_obj gets us a clean Object.*/
++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
++
++ if (!obj)
++ return obj;
++
++ dev->n_obj++;
++
++ /* Now sweeten it up... */
++
++ memset(obj, 0, sizeof(struct yaffs_obj));
++ obj->being_created = 1;
++
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0;
++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
++ INIT_LIST_HEAD(&(obj->hard_links));
++ INIT_LIST_HEAD(&(obj->hash_link));
++ INIT_LIST_HEAD(&obj->siblings);
++
++ /* Now make the directory sane */
++ if (dev->root_dir) {
++ obj->parent = dev->root_dir;
++ list_add(&(obj->siblings),
++ &dev->root_dir->variant.dir_variant.children);
++ }
++
++ /* Add it to the lost and found directory.
++ * NB Can't put root or lost-n-found in lost-n-found so
++ * check if lost-n-found exists first
++ */
++ if (dev->lost_n_found)
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++
++ obj->being_created = 0;
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return obj;
++}
++
++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
++{
++ int i;
++ int l = 999;
++ int lowest = 999999;
++
++ /* Search for the shortest list or one that
++ * isn't too long.
++ */
++
++ for (i = 0; i < 10 && lowest > 4; i++) {
++ dev->bucket_finder++;
++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
++ lowest = dev->obj_bucket[dev->bucket_finder].count;
++ l = dev->bucket_finder;
++ }
++ }
++
++ return l;
++}
++
++static int yaffs_new_obj_id(struct yaffs_dev *dev)
++{
++ int bucket = yaffs_find_nice_bucket(dev);
++ int found = 0;
++ struct list_head *i;
++ u32 n = (u32) bucket;
++
++ /* Now find an object value that has not already been taken
++ * by scanning the list.
++ */
++
++ while (!found) {
++ found = 1;
++ n += YAFFS_NOBJECT_BUCKETS;
++ if (1 || dev->obj_bucket[bucket].count > 0) {
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* If there is already one in the list */
++ if (i && list_entry(i, struct yaffs_obj,
++ hash_link)->obj_id == n) {
++ found = 0;
++ }
++ }
++ }
++ }
++ return n;
++}
++
++static void yaffs_hash_obj(struct yaffs_obj *in)
++{
++ int bucket = yaffs_hash_fn(in->obj_id);
++ struct yaffs_dev *dev = in->my_dev;
++
++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
++ dev->obj_bucket[bucket].count++;
++}
++
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
++{
++ int bucket = yaffs_hash_fn(number);
++ struct list_head *i;
++ struct yaffs_obj *in;
++
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* Look if it is in the list */
++ in = list_entry(i, struct yaffs_obj, hash_link);
++ if (in->obj_id == number) {
++ /* Don't show if it is defered free */
++ if (in->defered_free)
++ return NULL;
++ return in;
++ }
++ }
++
++ return NULL;
++}
++
++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++ struct yaffs_tnode *tn = NULL;
++
++ if (number < 0)
++ number = yaffs_new_obj_id(dev);
++
++ if (type == YAFFS_OBJECT_TYPE_FILE) {
++ tn = yaffs_get_tnode(dev);
++ if (!tn)
++ return NULL;
++ }
++
++ the_obj = yaffs_alloc_empty_obj(dev);
++ if (!the_obj) {
++ if (tn)
++ yaffs_free_tnode(dev, tn);
++ return NULL;
++ }
++
++ the_obj->fake = 0;
++ the_obj->rename_allowed = 1;
++ the_obj->unlink_allowed = 1;
++ the_obj->obj_id = number;
++ yaffs_hash_obj(the_obj);
++ the_obj->variant_type = type;
++ yaffs_load_current_time(the_obj, 1, 1);
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ the_obj->variant.file_variant.file_size = 0;
++ the_obj->variant.file_variant.scanned_size = 0;
++ the_obj->variant.file_variant.shrink_size =
++ yaffs_max_file_size(dev);
++ the_obj->variant.file_variant.top_level = 0;
++ the_obj->variant.file_variant.top = tn;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* No action required */
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* todo this should not happen */
++ break;
++ }
++ return the_obj;
++}
++
++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
++ int number, u32 mode)
++{
++
++ struct yaffs_obj *obj =
++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++
++ if (!obj)
++ return NULL;
++
++ obj->fake = 1; /* it is fake so it might not use NAND */
++ obj->rename_allowed = 0;
++ obj->unlink_allowed = 0;
++ obj->deleted = 0;
++ obj->unlinked = 0;
++ obj->yst_mode = mode;
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0; /* Not a valid chunk. */
++ return obj;
++
++}
++
++
++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ int i;
++
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++ yaffs_init_raw_tnodes_and_objs(dev);
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
++ dev->obj_bucket[i].count = 0;
++ }
++}
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++
++ if (number > 0)
++ the_obj = yaffs_find_by_number(dev, number);
++
++ if (!the_obj)
++ the_obj = yaffs_new_obj(dev, number, type);
++
++ return the_obj;
++
++}
++
++YCHAR *yaffs_clone_str(const YCHAR *str)
++{
++ YCHAR *new_str = NULL;
++ int len;
++
++ if (!str)
++ str = _Y("");
++
++ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
++ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
++ if (new_str) {
++ strncpy(new_str, str, len);
++ new_str[len] = 0;
++ }
++ return new_str;
++
++}
++/*
++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ * create dir/a : update dir's mtime/ctime
++ * rm dir/a: update dir's mtime/ctime
++ * modify dir/a: don't update dir's mtimme/ctime
++ *
++ * This can be handled immediately or defered. Defering helps reduce the number
++ * of updates when many files in a directory are changed within a brief period.
++ *
++ * If the directory updating is defered then yaffs_update_dirty_dirs must be
++ * called periodically.
++ */
++
++static void yaffs_update_parent(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj)
++ return;
++ dev = obj->my_dev;
++ obj->dirty = 1;
++ yaffs_load_current_time(obj, 0, 1);
++ if (dev->param.defered_dir_update) {
++ struct list_head *link = &obj->variant.dir_variant.dirty;
++
++ if (list_empty(link)) {
++ list_add(link, &dev->dirty_dirs);
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Added object %d to dirty directories",
++ obj->obj_id);
++ }
++
++ } else {
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
++{
++ struct list_head *link;
++ struct yaffs_obj *obj;
++ struct yaffs_dir_var *d_s;
++ union yaffs_obj_var *o_v;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
++
++ while (!list_empty(&dev->dirty_dirs)) {
++ link = dev->dirty_dirs.next;
++ list_del_init(link);
++
++ d_s = list_entry(link, struct yaffs_dir_var, dirty);
++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
++ obj = list_entry(o_v, struct yaffs_obj, variant);
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
++ obj->obj_id);
++
++ if (obj->dirty)
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++/*
++ * Mknod (create) a new object.
++ * equiv_obj only has meaning for a hard link;
++ * alias_str only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
++ struct yaffs_obj *parent,
++ const YCHAR *name,
++ u32 mode,
++ u32 uid,
++ u32 gid,
++ struct yaffs_obj *equiv_obj,
++ const YCHAR *alias_str, u32 rdev)
++{
++ struct yaffs_obj *in;
++ YCHAR *str = NULL;
++ struct yaffs_dev *dev = parent->my_dev;
++
++ /* Check if the entry exists.
++ * If it does then fail the call since we don't want a dup. */
++ if (yaffs_find_by_name(parent, name))
++ return NULL;
++
++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ str = yaffs_clone_str(alias_str);
++ if (!str)
++ return NULL;
++ }
++
++ in = yaffs_new_obj(dev, -1, type);
++
++ if (!in) {
++ kfree(str);
++ return NULL;
++ }
++
++ in->hdr_chunk = 0;
++ in->valid = 1;
++ in->variant_type = type;
++
++ in->yst_mode = mode;
++
++ yaffs_attribs_init(in, gid, uid, rdev);
++
++ in->n_data_chunks = 0;
++
++ yaffs_set_obj_name(in, name);
++ in->dirty = 1;
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ in->my_dev = parent->my_dev;
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.alias = str;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardlink_variant.equiv_obj = equiv_obj;
++ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
++ list_add(&in->hard_links, &equiv_obj->hard_links);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* do nothing */
++ break;
++ }
++
++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
++ /* Could not create the object header, fail */
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ if (in)
++ yaffs_update_parent(parent);
++
++ return in;
++}
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++ uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++ mode, uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++ uid, gid, NULL, NULL, rdev);
++}
++
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++ uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_link_obj returns the object id of the equivalent object.*/
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++ struct yaffs_obj *equiv_obj)
++{
++ /* Get the real object in case we were fed a hard link obj */
++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
++
++ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
++ parent, name, 0, 0, 0,
++ equiv_obj, NULL, 0))
++ return equiv_obj;
++
++ return NULL;
++
++}
++
++
++
++/*---------------------- Block Management and Page Allocation -------------*/
++
++static void yaffs_deinit_blocks(struct yaffs_dev *dev)
++{
++ if (dev->block_info_alt && dev->block_info)
++ vfree(dev->block_info);
++ else
++ kfree(dev->block_info);
++
++ dev->block_info_alt = 0;
++
++ dev->block_info = NULL;
++
++ if (dev->chunk_bits_alt && dev->chunk_bits)
++ vfree(dev->chunk_bits);
++ else
++ kfree(dev->chunk_bits);
++ dev->chunk_bits_alt = 0;
++ dev->chunk_bits = NULL;
++}
++
++static int yaffs_init_blocks(struct yaffs_dev *dev)
++{
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ dev->block_info = NULL;
++ dev->chunk_bits = NULL;
++ dev->alloc_block = -1; /* force it to get a new one */
++
++ /* If the first allocation strategy fails, thry the alternate one */
++ dev->block_info =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
++ if (!dev->block_info) {
++ dev->block_info =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_info));
++ dev->block_info_alt = 1;
++ } else {
++ dev->block_info_alt = 0;
++ }
++
++ if (!dev->block_info)
++ goto alloc_error;
++
++ /* Set up dynamic blockinfo stuff. Round up bytes. */
++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
++ dev->chunk_bits =
++ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
++ if (!dev->chunk_bits) {
++ dev->chunk_bits =
++ vmalloc(dev->chunk_bit_stride * n_blocks);
++ dev->chunk_bits_alt = 1;
++ } else {
++ dev->chunk_bits_alt = 0;
++ }
++ if (!dev->chunk_bits)
++ goto alloc_error;
++
++
++ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
++ return YAFFS_OK;
++
++alloc_error:
++ yaffs_deinit_blocks(dev);
++ return YAFFS_FAIL;
++}
++
++
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
++ int erased_ok = 0;
++ int i;
++
++ /* If the block is still healthy erase it and mark as clean.
++ * If the block has had a data failure, then retire it.
++ */
++
++ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++ "yaffs_block_became_dirty block %d state %d %s",
++ block_no, bi->block_state,
++ (bi->needs_retiring) ? "needs retiring" : "");
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
++
++ /* If this is the block being garbage collected then stop gc'ing */
++ if (block_no == dev->gc_block)
++ dev->gc_block = 0;
++
++ /* If this block is currently the best candidate for gc
++ * then drop as a candidate */
++ if (block_no == dev->gc_dirtiest) {
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ }
++
++ if (!bi->needs_retiring) {
++ yaffs2_checkpt_invalidate(dev);
++ erased_ok = yaffs_erase_block(dev, block_no);
++ if (!erased_ok) {
++ dev->n_erase_failures++;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Erasure failed %d", block_no);
++ }
++ }
++
++ /* Verify erasure if needed */
++ if (erased_ok &&
++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
++ !yaffs_skip_verification(dev))) {
++ for (i = 0; i < dev->param.chunks_per_block; i++) {
++ if (!yaffs_check_chunk_erased(dev,
++ block_no * dev->param.chunks_per_block + i)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ ">>Block %d erasure supposedly OK, but chunk %d not erased",
++ block_no, i);
++ }
++ }
++ }
++
++ if (!erased_ok) {
++ /* We lost a block of free space */
++ dev->n_free_chunks -= dev->param.chunks_per_block;
++ yaffs_retire_block(dev, block_no);
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d retired", block_no);
++ return;
++ }
++
++ /* Clean it up... */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ bi->seq_number = 0;
++ dev->n_erased_blocks++;
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++ bi->has_shrink_hdr = 0;
++ bi->skip_erased_check = 1; /* Clean, so no need to check */
++ bi->gc_prioritise = 0;
++ bi->has_summary = 0;
++
++ yaffs_clear_chunk_bits(dev, block_no);
++
++ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
++}
++
++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int old_chunk, u8 *buffer)
++{
++ int new_chunk;
++ int mark_flash = 1;
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj *object;
++ int matching_chunk;
++ int ret_val = YAFFS_OK;
++
++ memset(&tags, 0, sizeof(tags));
++ yaffs_rd_chunk_tags_nand(dev, old_chunk,
++ buffer, &tags);
++ object = yaffs_find_by_number(dev, tags.obj_id);
++
++ yaffs_trace(YAFFS_TRACE_GC_DETAIL,
++ "Collecting chunk in block %d, %d %d %d ",
++ dev->gc_chunk, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++
++ if (object && !yaffs_skip_verification(dev)) {
++ if (tags.chunk_id == 0)
++ matching_chunk =
++ object->hdr_chunk;
++ else if (object->soft_del)
++ /* Defeat the test */
++ matching_chunk = old_chunk;
++ else
++ matching_chunk =
++ yaffs_find_chunk_in_file
++ (object, tags.chunk_id,
++ NULL);
++
++ if (old_chunk != matching_chunk)
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "gc: page in gc mismatch: %d %d %d %d",
++ old_chunk,
++ matching_chunk,
++ tags.obj_id,
++ tags.chunk_id);
++ }
++
++ if (!object) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "page %d in gc has no object: %d %d %d ",
++ old_chunk,
++ tags.obj_id, tags.chunk_id,
++ tags.n_bytes);
++ }
++
++ if (object &&
++ object->deleted &&
++ object->soft_del && tags.chunk_id != 0) {
++ /* Data chunk in a soft deleted file,
++ * throw it away.
++ * It's a soft deleted data chunk,
++ * No need to copy this, just forget
++ * about it and fix up the object.
++ */
++
++ /* Free chunks already includes
++ * softdeleted chunks, how ever this
++ * chunk is going to soon be really
++ * deleted which will increment free
++ * chunks. We have to decrement free
++ * chunks so this works out properly.
++ */
++ dev->n_free_chunks--;
++ bi->soft_del_pages--;
++
++ object->n_data_chunks--;
++ if (object->n_data_chunks <= 0) {
++ /* remeber to clean up obj */
++ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
++ dev->n_clean_ups++;
++ }
++ mark_flash = 0;
++ } else if (object) {
++ /* It's either a data chunk in a live
++ * file or an ObjectHeader, so we're
++ * interested in it.
++ * NB Need to keep the ObjectHeaders of
++ * deleted files until the whole file
++ * has been deleted off
++ */
++ tags.serial_number++;
++ dev->n_gc_copies++;
++
++ if (tags.chunk_id == 0) {
++ /* It is an object Id,
++ * We need to nuke the
++ * shrinkheader flags since its
++ * work is done.
++ * Also need to clean up
++ * shadowing.
++ */
++ struct yaffs_obj_hdr *oh;
++ oh = (struct yaffs_obj_hdr *) buffer;
++
++ oh->is_shrink = 0;
++ tags.extra_is_shrink = 0;
++ oh->shadows_obj = 0;
++ oh->inband_shadowed_obj_id = 0;
++ tags.extra_shadows = 0;
++
++ /* Update file size */
++ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++ yaffs_oh_size_load(oh,
++ object->variant.file_variant.file_size);
++ tags.extra_file_size =
++ object->variant.file_variant.file_size;
++ }
++
++ yaffs_verify_oh(object, oh, &tags, 1);
++ new_chunk =
++ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
++ } else {
++ new_chunk =
++ yaffs_write_new_chunk(dev, buffer, &tags, 1);
++ }
++
++ if (new_chunk < 0) {
++ ret_val = YAFFS_FAIL;
++ } else {
++
++ /* Now fix up the Tnodes etc. */
++
++ if (tags.chunk_id == 0) {
++ /* It's a header */
++ object->hdr_chunk = new_chunk;
++ object->serial = tags.serial_number;
++ } else {
++ /* It's a data chunk */
++ yaffs_put_chunk_in_file(object, tags.chunk_id,
++ new_chunk, 0);
++ }
++ }
++ }
++ if (ret_val == YAFFS_OK)
++ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
++ return ret_val;
++}
++
++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
++{
++ int old_chunk;
++ int ret_val = YAFFS_OK;
++ int i;
++ int is_checkpt_block;
++ int max_copies;
++ int chunks_before = yaffs_get_erased_chunks(dev);
++ int chunks_after;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
++
++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d, in use %d, shrink %d, whole_block %d",
++ block, bi->pages_in_use, bi->has_shrink_hdr,
++ whole_block);
++
++ /*yaffs_verify_free_chunks(dev); */
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
++
++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
++
++ dev->gc_disable = 1;
++
++ yaffs_summary_gc(dev, block);
++
++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d that has no chunks in use",
++ block);
++ yaffs_block_became_dirty(dev, block);
++ } else {
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_verify_blk(dev, bi, block);
++
++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
++
++ for (/* init already done */ ;
++ ret_val == YAFFS_OK &&
++ dev->gc_chunk < dev->param.chunks_per_block &&
++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
++ max_copies > 0;
++ dev->gc_chunk++, old_chunk++) {
++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
++ /* Page is in use and might need to be copied */
++ max_copies--;
++ ret_val = yaffs_gc_process_chunk(dev, bi,
++ old_chunk, buffer);
++ }
++ }
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ yaffs_verify_collected_blk(dev, bi, block);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ /*
++ * The gc did not complete. Set block state back to FULL
++ * because checkpointing does not restore gc.
++ */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ } else {
++ /* The gc completed. */
++ /* Do any required cleanups */
++ for (i = 0; i < dev->n_clean_ups; i++) {
++ /* Time to delete the file too */
++ struct yaffs_obj *object =
++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
++ if (object) {
++ yaffs_free_tnode(dev,
++ object->variant.file_variant.top);
++ object->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: About to finally delete object %d",
++ object->obj_id);
++ yaffs_generic_obj_del(object);
++ object->my_dev->n_deleted_files--;
++ }
++
++ }
++ chunks_after = yaffs_get_erased_chunks(dev);
++ if (chunks_before >= chunks_after)
++ yaffs_trace(YAFFS_TRACE_GC,
++ "gc did not increase free chunks before %d after %d",
++ chunks_before, chunks_after);
++ dev->gc_block = 0;
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ dev->gc_disable = 0;
++
++ return ret_val;
++}
++
++/*
++ * find_gc_block() selects the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
++ int aggressive, int background)
++{
++ int i;
++ int iterations;
++ unsigned selected = 0;
++ int prioritised = 0;
++ int prioritised_exist = 0;
++ struct yaffs_block_info *bi;
++ int threshold;
++
++ /* First let's see if we need to grab a prioritised block */
++ if (dev->has_pending_prioritised_gc && !aggressive) {
++ dev->gc_dirtiest = 0;
++ bi = dev->block_info;
++ for (i = dev->internal_start_block;
++ i <= dev->internal_end_block && !selected; i++) {
++
++ if (bi->gc_prioritise) {
++ prioritised_exist = 1;
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ selected = i;
++ prioritised = 1;
++ }
++ }
++ bi++;
++ }
++
++ /*
++ * If there is a prioritised block and none was selected then
++ * this happened because there is at least one old dirty block
++ * gumming up the works. Let's gc the oldest dirty block.
++ */
++
++ if (prioritised_exist &&
++ !selected && dev->oldest_dirty_block > 0)
++ selected = dev->oldest_dirty_block;
++
++ if (!prioritised_exist) /* None found, so we can clear this */
++ dev->has_pending_prioritised_gc = 0;
++ }
++
++ /* If we're doing aggressive GC then we are happy to take a less-dirty
++ * block, and search harder.
++ * else (leasurely gc), then we only bother to do this if the
++ * block has only a few pages in use.
++ */
++
++ if (!selected) {
++ int pages_used;
++ int n_blocks =
++ dev->internal_end_block - dev->internal_start_block + 1;
++ if (aggressive) {
++ threshold = dev->param.chunks_per_block;
++ iterations = n_blocks;
++ } else {
++ int max_threshold;
++
++ if (background)
++ max_threshold = dev->param.chunks_per_block / 2;
++ else
++ max_threshold = dev->param.chunks_per_block / 8;
++
++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++
++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++ if (threshold > max_threshold)
++ threshold = max_threshold;
++
++ iterations = n_blocks / 16 + 1;
++ if (iterations > 100)
++ iterations = 100;
++ }
++
++ for (i = 0;
++ i < iterations &&
++ (dev->gc_dirtiest < 1 ||
++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
++ i++) {
++ dev->gc_block_finder++;
++ if (dev->gc_block_finder < dev->internal_start_block ||
++ dev->gc_block_finder > dev->internal_end_block)
++ dev->gc_block_finder =
++ dev->internal_start_block;
++
++ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
++
++ pages_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ pages_used < dev->param.chunks_per_block &&
++ (dev->gc_dirtiest < 1 ||
++ pages_used < dev->gc_pages_in_use) &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ dev->gc_dirtiest = dev->gc_block_finder;
++ dev->gc_pages_in_use = pages_used;
++ }
++ }
++
++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
++ selected = dev->gc_dirtiest;
++ }
++
++ /*
++ * If nothing has been selected for a while, try the oldest dirty
++ * because that's gumming up the works.
++ */
++
++ if (!selected && dev->param.is_yaffs2 &&
++ dev->gc_not_done >= (background ? 10 : 20)) {
++ yaffs2_find_oldest_dirty_seq(dev);
++ if (dev->oldest_dirty_block > 0) {
++ selected = dev->oldest_dirty_block;
++ dev->gc_dirtiest = selected;
++ dev->oldest_dirty_gc_count++;
++ bi = yaffs_get_block_info(dev, selected);
++ dev->gc_pages_in_use =
++ bi->pages_in_use - bi->soft_del_pages;
++ } else {
++ dev->gc_not_done = 0;
++ }
++ }
++
++ if (selected) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC Selected block %d with %d free, prioritised:%d",
++ selected,
++ dev->param.chunks_per_block - dev->gc_pages_in_use,
++ prioritised);
++
++ dev->n_gc_blocks++;
++ if (background)
++ dev->bg_gcs++;
++
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ dev->gc_not_done = 0;
++ if (dev->refresh_skip > 0)
++ dev->refresh_skip--;
++ } else {
++ dev->gc_not_done++;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
++ dev->gc_block_finder, dev->gc_not_done, threshold,
++ dev->gc_dirtiest, dev->gc_pages_in_use,
++ dev->oldest_dirty_block, background ? " bg" : "");
++ }
++
++ return selected;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_check_gc(struct yaffs_dev *dev, int background)
++{
++ int aggressive = 0;
++ int gc_ok = YAFFS_OK;
++ int max_tries = 0;
++ int min_erased;
++ int erased_chunks;
++ int checkpt_block_adjust;
++
++ if (dev->param.gc_control_fn &&
++ (dev->param.gc_control_fn(dev) & 1) == 0)
++ return YAFFS_OK;
++
++ if (dev->gc_disable)
++ /* Bail out so we don't get recursive gc */
++ return YAFFS_OK;
++
++ /* This loop should pass the first time.
++ * Only loops here if the collection does not increase space.
++ */
++
++ do {
++ max_tries++;
++
++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
++
++ min_erased =
++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
++ erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ /* If we need a block soon then do aggressive gc. */
++ if (dev->n_erased_blocks < min_erased)
++ aggressive = 1;
++ else {
++ if (!background
++ && erased_chunks > (dev->n_free_chunks / 4))
++ break;
++
++ if (dev->gc_skip > 20)
++ dev->gc_skip = 20;
++ if (erased_chunks < dev->n_free_chunks / 2 ||
++ dev->gc_skip < 1 || background)
++ aggressive = 0;
++ else {
++ dev->gc_skip--;
++ break;
++ }
++ }
++
++ dev->gc_skip = 5;
++
++ /* If we don't already have a block being gc'd then see if we
++ * should start another */
++
++ if (dev->gc_block < 1 && !aggressive) {
++ dev->gc_block = yaffs2_find_refresh_block(dev);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++ if (dev->gc_block < 1) {
++ dev->gc_block =
++ yaffs_find_gc_block(dev, aggressive, background);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ if (dev->gc_block > 0) {
++ dev->all_gcs++;
++ if (!aggressive)
++ dev->passive_gc_count++;
++
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC n_erased_blocks %d aggressive %d",
++ dev->n_erased_blocks, aggressive);
++
++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
++ }
++
++ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
++ dev->gc_block > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
++ dev->n_erased_blocks, max_tries,
++ dev->gc_block);
++ }
++ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
++ (dev->gc_block > 0) && (max_tries < 2));
++
++ return aggressive ? gc_ok : YAFFS_OK;
++}
++
++/*
++ * yaffs_bg_gc()
++ * Garbage collects. Intended to be called from a background thread.
++ * Returns non-zero if at least half the free chunks are erased.
++ */
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
++{
++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
++
++ yaffs_check_gc(dev, 1);
++ return erased_chunks > dev->n_free_chunks / 2;
++}
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
++{
++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
++
++ if (nand_chunk >= 0)
++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
++ buffer, NULL);
++ else {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not found zero instead",
++ nand_chunk);
++ /* get sane (zero) data if you read a hole */
++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
++ return 0;
++ }
++
++}
++
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn)
++{
++ int block;
++ int page;
++ struct yaffs_ext_tags tags;
++ struct yaffs_block_info *bi;
++
++ if (chunk_id <= 0)
++ return;
++
++ dev->n_deletions++;
++ block = chunk_id / dev->param.chunks_per_block;
++ page = chunk_id % dev->param.chunks_per_block;
++
++ if (!yaffs_check_chunk_bit(dev, block, page))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Deleting invalid chunk %d", chunk_id);
++
++ bi = yaffs_get_block_info(dev, block);
++
++ yaffs2_update_oldest_dirty_seq(dev, block, bi);
++
++ yaffs_trace(YAFFS_TRACE_DELETION,
++ "line %d delete of chunk %d",
++ lyn, chunk_id);
++
++ if (!dev->param.is_yaffs2 && mark_flash &&
++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
++
++ memset(&tags, 0, sizeof(tags));
++ tags.is_deleted = 1;
++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
++ yaffs_handle_chunk_update(dev, chunk_id, &tags);
++ } else {
++ dev->n_unmarked_deletions++;
++ }
++
++ /* Pull out of the management area.
++ * If the whole block became dirty, this will kick off an erasure.
++ */
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
++ bi->block_state == YAFFS_BLOCK_STATE_FULL ||
++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->n_free_chunks++;
++ yaffs_clear_chunk_bit(dev, block, page);
++ bi->pages_in_use--;
++
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ yaffs_block_became_dirty(dev, block);
++ }
++ }
++}
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve)
++{
++ /* Find old chunk Need to do this to get serial number
++ * Write new one and patch into tree.
++ * Invalidate old tags.
++ */
++
++ int prev_chunk_id;
++ struct yaffs_ext_tags prev_tags;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_dev *dev = in->my_dev;
++
++ yaffs_check_gc(dev, 0);
++
++ /* Get the previous chunk at this location in the file if it exists.
++ * If it does not exist then put a zero into the tree. This creates
++ * the tnode now, rather than later when it is harder to clean up.
++ */
++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
++ if (prev_chunk_id < 1 &&
++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
++ return 0;
++
++ /* Set up new tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++
++ new_tags.chunk_id = inode_chunk;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number =
++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
++ new_tags.n_bytes = n_bytes;
++
++ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Writing %d bytes to chunk!!!!!!!!!",
++ n_bytes);
++ BUG();
++ }
++
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
++
++ if (new_chunk_id > 0) {
++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ yaffs_verify_file_sane(in);
++ }
++ return new_chunk_id;
++
++}
++
++
++
++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
++ const YCHAR *name, const void *value, int size,
++ int flags)
++{
++ struct yaffs_xattr_mod xmod;
++ int result;
++
++ xmod.set = set;
++ xmod.name = name;
++ xmod.data = value;
++ xmod.size = size;
++ xmod.flags = flags;
++ xmod.result = -ENOSPC;
++
++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
++
++ if (result > 0)
++ return xmod.result;
++ else
++ return -ENOSPC;
++}
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++ struct yaffs_xattr_mod *xmod)
++{
++ int retval = 0;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer = buffer + x_offs;
++
++ if (xmod->set)
++ retval =
++ nval_set(x_buffer, x_size, xmod->name, xmod->data,
++ xmod->size, xmod->flags);
++ else
++ retval = nval_del(x_buffer, x_size, xmod->name);
++
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ xmod->result = retval;
++
++ return retval;
++}
++
++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
++ void *value, int size)
++{
++ char *buffer = NULL;
++ int result;
++ struct yaffs_ext_tags tags;
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer;
++ int retval = 0;
++
++ if (obj->hdr_chunk < 1)
++ return -ENODATA;
++
++ /* If we know that the object has no xattribs then don't do all the
++ * reading and parsing.
++ */
++ if (obj->xattr_known && !obj->has_xattr) {
++ if (name)
++ return -ENODATA;
++ else
++ return 0;
++ }
++
++ buffer = (char *)yaffs_get_temp_buffer(dev);
++ if (!buffer)
++ return -ENOMEM;
++
++ result =
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
++
++ if (result != YAFFS_OK)
++ retval = -ENOENT;
++ else {
++ x_buffer = buffer + x_offs;
++
++ if (!obj->xattr_known) {
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ }
++
++ if (name)
++ retval = nval_get(x_buffer, x_size, name, value, size);
++ else
++ retval = nval_list(x_buffer, x_size, value, size);
++ }
++ yaffs_release_temp_buffer(dev, (u8 *) buffer);
++ return retval;
++}
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++ const void *value, int size, int flags)
++{
++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
++}
++
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
++{
++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
++}
++
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++ int size)
++{
++ return yaffs_do_xattrib_fetch(obj, name, value, size);
++}
++
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
++{
++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
++}
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
++{
++ u8 *buf;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++
++ if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
++ return;
++
++ dev = in->my_dev;
++ in->lazy_loaded = 0;
++ buf = yaffs_get_temp_buffer(dev);
++
++ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
++ oh = (struct yaffs_obj_hdr *)buf;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ yaffs_set_obj_name_from_oh(in, oh);
++
++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ in->variant.symlink_variant.alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.symlink_variant.alias)
++ alloc_failed = 1; /* Not returned */
++ }
++ yaffs_release_temp_buffer(dev, buf);
++}
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
++ const YCHAR *oh_name, int buff_size)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ if (dev->param.auto_unicode) {
++ if (*oh_name) {
++ /* It is an ASCII name, do an ASCII to
++ * unicode conversion */
++ const char *ascii_oh_name = (const char *)oh_name;
++ int n = buff_size - 1;
++ while (n > 0 && *ascii_oh_name) {
++ *name = *ascii_oh_name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ strncpy(name, oh_name + 1, buff_size - 1);
++ }
++ } else {
++#else
++ (void) dev;
++ {
++#endif
++ strncpy(name, oh_name, buff_size - 1);
++ }
++}
++
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
++ const YCHAR *name)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++
++ int is_ascii;
++ YCHAR *w;
++
++ if (dev->param.auto_unicode) {
++
++ is_ascii = 1;
++ w = name;
++
++ /* Figure out if the name will fit in ascii character set */
++ while (is_ascii && *w) {
++ if ((*w) & 0xff00)
++ is_ascii = 0;
++ w++;
++ }
++
++ if (is_ascii) {
++ /* It is an ASCII name, so convert unicode to ascii */
++ char *ascii_oh_name = (char *)oh_name;
++ int n = YAFFS_MAX_NAME_LENGTH - 1;
++ while (n > 0 && *name) {
++ *ascii_oh_name = *name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ /* Unicode name, so save starting at the second YCHAR */
++ *oh_name = 0;
++ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
++ }
++ } else {
++#else
++ dev = dev;
++ {
++#endif
++ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
++ }
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
++{
++
++ struct yaffs_block_info *bi;
++ struct yaffs_dev *dev = in->my_dev;
++ int prev_chunk_id;
++ int ret_val = 0;
++ int result = 0;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_ext_tags old_tags;
++ const YCHAR *alias = NULL;
++ u8 *buffer = NULL;
++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj_hdr *oh = NULL;
++ loff_t file_size = 0;
++
++ strcpy(old_name, _Y("silly old name"));
++
++ if (in->fake && in != dev->root_dir && !force && !xmod)
++ return ret_val;
++
++ yaffs_check_gc(dev, 0);
++ yaffs_check_obj_details_loaded(in);
++
++ buffer = yaffs_get_temp_buffer(in->my_dev);
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ prev_chunk_id = in->hdr_chunk;
++
++ if (prev_chunk_id > 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
++ buffer, &old_tags);
++
++ yaffs_verify_oh(in, oh, &old_tags, 0);
++ memcpy(old_name, oh->name, sizeof(oh->name));
++ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
++ } else {
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ }
++
++ oh->type = in->variant_type;
++ oh->yst_mode = in->yst_mode;
++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
++
++ yaffs_load_attribs_oh(oh, in);
++
++ if (in->parent)
++ oh->parent_obj_id = in->parent->obj_id;
++ else
++ oh->parent_obj_id = 0;
++
++ if (name && *name) {
++ memset(oh->name, 0, sizeof(oh->name));
++ yaffs_load_oh_from_name(dev, oh->name, name);
++ } else if (prev_chunk_id > 0) {
++ memcpy(oh->name, old_name, sizeof(oh->name));
++ } else {
++ memset(oh->name, 0, sizeof(oh->name));
++ }
++
++ oh->is_shrink = is_shrink;
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Should not happen */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
++ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
++ file_size = in->variant.file_variant.file_size;
++ yaffs_oh_size_load(oh, file_size);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = in->variant.symlink_variant.alias;
++ if (!alias)
++ alias = _Y("no alias");
++ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++ break;
++ }
++
++ /* process any xattrib modifications */
++ if (xmod)
++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
++
++ /* Tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++ in->serial++;
++ new_tags.chunk_id = 0;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number = in->serial;
++
++ /* Add extra info for file header */
++ new_tags.extra_available = 1;
++ new_tags.extra_parent_id = oh->parent_obj_id;
++ new_tags.extra_file_size = file_size;
++ new_tags.extra_is_shrink = oh->is_shrink;
++ new_tags.extra_equiv_id = oh->equiv_id;
++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
++ new_tags.extra_obj_type = in->variant_type;
++ yaffs_verify_oh(in, oh, &new_tags, 1);
++
++ /* Create new chunk in NAND */
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags,
++ (prev_chunk_id > 0) ? 1 : 0);
++
++ if (buffer)
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (new_chunk_id < 0)
++ return new_chunk_id;
++
++ in->hdr_chunk = new_chunk_id;
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ if (!yaffs_obj_cache_dirty(in))
++ in->dirty = 0;
++
++ /* If this was a shrink, then mark the block
++ * that the chunk lives on */
++ if (is_shrink) {
++ bi = yaffs_get_block_info(in->my_dev,
++ new_chunk_id /
++ in->my_dev->param.chunks_per_block);
++ bi->has_shrink_hdr = 1;
++ }
++
++
++ return new_chunk_id;
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
++{
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ struct yaffs_cache *cache;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++ if ((start + n) < dev->data_bytes_per_chunk)
++ n_copy = n;
++ else
++ n_copy = dev->data_bytes_per_chunk - start;
++
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ /* If the chunk is already in the cache or it is less than
++ * a whole chunk or we're using inband tags then use the cache
++ * (if there is caching) else bypass the cache.
++ */
++ if (cache || n_copy != dev->data_bytes_per_chunk ||
++ dev->param.inband_tags) {
++ if (dev->param.n_caches > 0) {
++
++ /* If we can't find the data in the cache,
++ * then load it up. */
++
++ if (!cache) {
++ cache =
++ yaffs_grab_chunk_cache(in->my_dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ cache->n_bytes = 0;
++ }
++
++ yaffs_use_cache(dev, cache, 0);
++
++ cache->locked = 1;
++
++ memcpy(buffer, &cache->data[start], n_copy);
++
++ cache->locked = 0;
++ } else {
++ /* Read into the local buffer then copy.. */
++
++ u8 *local_buffer =
++ yaffs_get_temp_buffer(dev);
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++
++ memcpy(buffer, &local_buffer[start], n_copy);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Read directly into the buffer. */
++ yaffs_rd_data_obj(in, chunk, buffer);
++ }
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ return n_done;
++}
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ int n_writeback;
++ loff_t start_write = offset;
++ int chunk_written = 0;
++ u32 n_bytes_read;
++ loff_t chunk_start;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0 && chunk_written >= 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++
++ if (((loff_t)chunk) *
++ dev->data_bytes_per_chunk + start != offset ||
++ start >= dev->data_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "AddrToChunk of offset %lld gives chunk %d start %d",
++ offset, chunk, start);
++ }
++ chunk++; /* File pos to chunk in file offset */
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++
++ if ((start + n) < dev->data_bytes_per_chunk) {
++ n_copy = n;
++
++ /* Now calculate how many bytes to write back....
++ * If we're overwriting and not writing to then end of
++ * file then we need to write back as much as was there
++ * before.
++ */
++
++ chunk_start = (((loff_t)(chunk - 1)) *
++ dev->data_bytes_per_chunk);
++
++ if (chunk_start > in->variant.file_variant.file_size)
++ n_bytes_read = 0; /* Past end of file */
++ else
++ n_bytes_read =
++ in->variant.file_variant.file_size -
++ chunk_start;
++
++ if (n_bytes_read > dev->data_bytes_per_chunk)
++ n_bytes_read = dev->data_bytes_per_chunk;
++
++ n_writeback =
++ (n_bytes_read >
++ (start + n)) ? n_bytes_read : (start + n);
++
++ if (n_writeback < 0 ||
++ n_writeback > dev->data_bytes_per_chunk)
++ BUG();
++
++ } else {
++ n_copy = dev->data_bytes_per_chunk - start;
++ n_writeback = dev->data_bytes_per_chunk;
++ }
++
++ if (n_copy != dev->data_bytes_per_chunk ||
++ !dev->param.cache_bypass_aligned ||
++ dev->param.inband_tags) {
++ /* An incomplete start or end chunk (or maybe both
++ * start and end chunk), or we're using inband tags,
++ * or we're forcing writes through the cache,
++ * so we want to use the cache buffers.
++ */
++ if (dev->param.n_caches > 0) {
++ struct yaffs_cache *cache;
++
++ /* If we can't find the data in the cache, then
++ * load the cache */
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ if (!cache &&
++ yaffs_check_alloc_available(dev, 1)) {
++ cache = yaffs_grab_chunk_cache(dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ } else if (cache &&
++ !cache->dirty &&
++ !yaffs_check_alloc_available(dev,
++ 1)) {
++ /* Drop the cache if it was a read cache
++ * item and no space check has been made
++ * for it.
++ */
++ cache = NULL;
++ }
++
++ if (cache) {
++ yaffs_use_cache(dev, cache, 1);
++ cache->locked = 1;
++
++ memcpy(&cache->data[start], buffer,
++ n_copy);
++
++ cache->locked = 0;
++ cache->n_bytes = n_writeback;
++
++ if (write_through) {
++ chunk_written =
++ yaffs_wr_data_obj
++ (cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ }
++ } else {
++ chunk_written = -1; /* fail write */
++ }
++ } else {
++ /* An incomplete start or end chunk (or maybe
++ * both start and end chunk). Read into the
++ * local buffer then copy over and write back.
++ */
++
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++ memcpy(&local_buffer[start], buffer, n_copy);
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk,
++ local_buffer,
++ n_writeback, 0);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Write directly from the buffer. */
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk, buffer,
++ dev->data_bytes_per_chunk, 0);
++
++ /* Since we've overwritten the cached data,
++ * we better invalidate it. */
++ yaffs_invalidate_chunk_cache(in, chunk);
++ }
++
++ if (chunk_written >= 0) {
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ }
++
++ /* Update file object */
++
++ if ((start_write + n_done) > in->variant.file_variant.file_size)
++ in->variant.file_variant.file_size = (start_write + n_done);
++
++ in->dirty = 1;
++ return n_done;
++}
++
++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++ yaffs2_handle_hole(in, offset);
++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
++}
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
++{
++
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++ int i;
++ int chunk_id;
++ u32 dummy;
++ int last_del;
++ int start_del;
++
++ if (old_size > 0)
++ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
++ else
++ last_del = 0;
++
++ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
++ &start_del, &dummy);
++ last_del++;
++ start_del++;
++
++ /* Delete backwards so that we don't end up with holes if
++ * power is lost part-way through the operation.
++ */
++ for (i = last_del; i >= start_del; i--) {
++ /* NB this could be optimised somewhat,
++ * eg. could retrieve the tags and write them without
++ * using yaffs_chunk_del
++ */
++
++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
++
++ if (chunk_id < 1)
++ continue;
++
++ if (chunk_id <
++ (dev->internal_start_block * dev->param.chunks_per_block) ||
++ chunk_id >=
++ ((dev->internal_end_block + 1) *
++ dev->param.chunks_per_block)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Found daft chunk_id %d for %d",
++ chunk_id, i);
++ } else {
++ in->n_data_chunks--;
++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
++ }
++ }
++}
++
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
++{
++ int new_full;
++ u32 new_partial;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
++
++ yaffs_prune_chunks(obj, new_size);
++
++ if (new_partial != 0) {
++ int last_chunk = 1 + new_full;
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ /* Rewrite the last chunk with its new size and zero pad */
++ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
++ memset(local_buffer + new_partial, 0,
++ dev->data_bytes_per_chunk - new_partial);
++
++ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
++ new_partial, 1);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++
++ obj->variant.file_variant.file_size = new_size;
++
++ yaffs_prune_tree(dev, &obj->variant.file_variant);
++}
++
++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
++{
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++
++ yaffs_flush_file_cache(in);
++ yaffs_invalidate_whole_cache(in);
++
++ yaffs_check_gc(dev, 0);
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ if (new_size == old_size)
++ return YAFFS_OK;
++
++ if (new_size > old_size) {
++ yaffs2_handle_hole(in, new_size);
++ in->variant.file_variant.file_size = new_size;
++ } else {
++ /* new_size < old_size */
++ yaffs_resize_file_down(in, new_size);
++ }
++
++ /* Write a new object header to reflect the resize.
++ * show we've shrunk the file, if need be
++ * Do this only if the file is not in the deleted directories
++ * and is not shadowed.
++ */
++ if (in->parent &&
++ !in->is_shadowed &&
++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ in->parent->obj_id != YAFFS_OBJECTID_DELETED)
++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
++
++ return YAFFS_OK;
++}
++
++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
++{
++ if (!in->dirty)
++ return YAFFS_OK;
++
++ yaffs_flush_file_cache(in);
++
++ if (data_sync)
++ return YAFFS_OK;
++
++ if (update_time)
++ yaffs_load_current_time(in, 0, 0);
++
++ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
++ YAFFS_OK : YAFFS_FAIL;
++}
++
++
++/* yaffs_del_file deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
++{
++ int ret_val;
++ int del_now = 0;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!in->my_inode)
++ del_now = 1;
++
++ if (del_now) {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->del_dir,
++ _Y("deleted"), 0, 0);
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: immediate deletion of file %d",
++ in->obj_id);
++ in->deleted = 1;
++ in->my_dev->n_deleted_files++;
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++ yaffs_soft_del_file(in);
++ } else {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++ return ret_val;
++}
++
++static int yaffs_del_file(struct yaffs_obj *in)
++{
++ int ret_val = YAFFS_OK;
++ int deleted; /* Need to cache value on stack if in is freed */
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++
++ if (in->n_data_chunks > 0) {
++ /* Use soft deletion if there is data in the file.
++ * That won't be the case if it has been resized to zero.
++ */
++ if (!in->unlinked)
++ ret_val = yaffs_unlink_file_if_needed(in);
++
++ deleted = in->deleted;
++
++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
++ in->deleted = 1;
++ deleted = 1;
++ in->my_dev->n_deleted_files++;
++ yaffs_soft_del_file(in);
++ }
++ return deleted ? YAFFS_OK : YAFFS_FAIL;
++ } else {
++ /* The file has no data chunks so we toss it immediately */
++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
++ in->variant.file_variant.top = NULL;
++ yaffs_generic_obj_del(in);
++
++ return YAFFS_OK;
++ }
++}
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
++{
++ return (obj &&
++ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++ !(list_empty(&obj->variant.dir_variant.children));
++}
++
++static int yaffs_del_dir(struct yaffs_obj *obj)
++{
++ /* First check that the directory is empty. */
++ if (yaffs_is_non_empty_dir(obj))
++ return YAFFS_FAIL;
++
++ return yaffs_generic_obj_del(obj);
++}
++
++static int yaffs_del_symlink(struct yaffs_obj *in)
++{
++ kfree(in->variant.symlink_variant.alias);
++ in->variant.symlink_variant.alias = NULL;
++
++ return yaffs_generic_obj_del(in);
++}
++
++static int yaffs_del_link(struct yaffs_obj *in)
++{
++ /* remove this hardlink from the list associated with the equivalent
++ * object
++ */
++ list_del_init(&in->hard_links);
++ return yaffs_generic_obj_del(in);
++}
++
++int yaffs_del_obj(struct yaffs_obj *obj)
++{
++ int ret_val = -1;
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ ret_val = yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!list_empty(&obj->variant.dir_variant.dirty)) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Remove object %d from dirty directories",
++ obj->obj_id);
++ list_del_init(&obj->variant.dir_variant.dirty);
++ }
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ ret_val = yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ ret_val = yaffs_del_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ ret_val = yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ ret_val = 0;
++ break; /* should not happen. */
++ }
++ return ret_val;
++}
++
++
++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
++ struct yaffs_obj *to_dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_add_obj_to_dir(to_dir, obj);
++ }
++}
++
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type)
++{
++ /* Tear down the old variant */
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ /* Nuke file data */
++ yaffs_resize_file(obj, 0);
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Put the children in lost and found. */
++ yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
++ if (!list_empty(&obj->variant.dir_variant.dirty))
++ list_del_init(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ /* Nuke symplink data */
++ kfree(obj->variant.symlink_variant.alias);
++ obj->variant.symlink_variant.alias = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ list_del_init(&obj->hard_links);
++ break;
++ default:
++ break;
++ }
++
++ memset(&obj->variant, 0, sizeof(obj->variant));
++
++ /*Set up new variant if the memset is not enough. */
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ default:
++ break;
++ }
++
++ obj->variant_type = type;
++
++ return obj;
++
++}
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj)
++{
++ int del_now = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (!obj->my_inode)
++ del_now = 1;
++
++ yaffs_update_parent(obj->parent);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ return yaffs_del_link(obj);
++ } else if (!list_empty(&obj->hard_links)) {
++ /* Curve ball: We're unlinking an object that has a hardlink.
++ *
++ * This problem arises because we are not strictly following
++ * The Linux link/inode model.
++ *
++ * We can't really delete the object.
++ * Instead, we do the following:
++ * - Select a hardlink.
++ * - Unhook it from the hard links
++ * - Move it from its parent directory so that the rename works.
++ * - Rename the object to the hardlink's name.
++ * - Delete the hardlink
++ */
++
++ struct yaffs_obj *hl;
++ struct yaffs_obj *parent;
++ int ret_val;
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
++ hard_links);
++
++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++ parent = hl->parent;
++
++ list_del_init(&hl->hard_links);
++
++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
++
++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
++
++ if (ret_val == YAFFS_OK)
++ ret_val = yaffs_generic_obj_del(hl);
++
++ return ret_val;
++
++ } else if (del_now) {
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ list_del_init(&obj->variant.dir_variant.dirty);
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ return yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ return YAFFS_FAIL;
++ }
++ } else if (yaffs_is_non_empty_dir(obj)) {
++ return YAFFS_FAIL;
++ } else {
++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++}
++
++static int yaffs_unlink_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->unlink_allowed)
++ return yaffs_unlink_worker(obj);
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
++{
++ struct yaffs_obj *obj;
++
++ obj = yaffs_find_by_name(dir, name);
++ return yaffs_unlink_obj(obj);
++}
++
++/* Note:
++ * If old_name is NULL then we take old_dir as the object to be renamed.
++ */
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
++ struct yaffs_obj *new_dir, const YCHAR *new_name)
++{
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *existing_target = NULL;
++ int force = 0;
++ int result;
++ struct yaffs_dev *dev;
++
++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ dev = old_dir->my_dev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ /* Special case for case insemsitive systems.
++ * While look-up is case insensitive, the name isn't.
++ * Therefore we might want to change x.txt to X.txt
++ */
++ if (old_dir == new_dir &&
++ old_name && new_name &&
++ strcmp(old_name, new_name) == 0)
++ force = 1;
++#endif
++
++ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ /* ENAMETOOLONG */
++ return YAFFS_FAIL;
++
++ if (old_name)
++ obj = yaffs_find_by_name(old_dir, old_name);
++ else{
++ obj = old_dir;
++ old_dir = obj->parent;
++ }
++
++ if (obj && obj->rename_allowed) {
++ /* Now handle an existing target, if there is one */
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++ if (yaffs_is_non_empty_dir(existing_target)) {
++ return YAFFS_FAIL; /* ENOTEMPTY */
++ } else if (existing_target && existing_target != obj) {
++ /* Nuke the target first, using shadowing,
++ * but only if it isn't the same object.
++ *
++ * Note we must disable gc here otherwise it can mess
++ * up the shadowing.
++ *
++ */
++ dev->gc_disable = 1;
++ yaffs_change_obj_name(obj, new_dir, new_name, force,
++ existing_target->obj_id);
++ existing_target->is_shadowed = 1;
++ yaffs_unlink_obj(existing_target);
++ dev->gc_disable = 0;
++ }
++
++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
++
++ yaffs_update_parent(old_dir);
++ if (new_dir != old_dir)
++ yaffs_update_parent(new_dir);
++
++ return result;
++ }
++ return YAFFS_FAIL;
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning)
++{
++ struct yaffs_obj *obj;
++
++ if (backward_scanning) {
++ /* Handle YAFFS2 case (backward scanning)
++ * If the shadowed object exists then ignore.
++ */
++ obj = yaffs_find_by_number(dev, obj_id);
++ if (obj)
++ return;
++ }
++
++ /* Let's create it (if it does not exist) assuming it is a file so that
++ * it can do shrinking etc.
++ * We put it in unlinked dir to be cleaned up after the scanning
++ */
++ obj =
++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
++ if (!obj)
++ return;
++ obj->is_shadowed = 1;
++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
++ obj->variant.file_variant.shrink_size = 0;
++ obj->valid = 1; /* So that we don't read any other info. */
++}
++
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
++{
++ struct list_head *lh;
++ struct list_head *save;
++ struct yaffs_obj *hl;
++ struct yaffs_obj *in;
++
++ list_for_each_safe(lh, save, hard_list) {
++ hl = list_entry(lh, struct yaffs_obj, hard_links);
++ in = yaffs_find_by_number(dev,
++ hl->variant.hardlink_variant.equiv_id);
++
++ if (in) {
++ /* Add the hardlink pointers */
++ hl->variant.hardlink_variant.equiv_obj = in;
++ list_add(&hl->hard_links, &in->hard_links);
++ } else {
++ /* Todo Need to report/handle this better.
++ * Got a problem... hardlink to a non-existant object
++ */
++ hl->variant.hardlink_variant.equiv_obj = NULL;
++ INIT_LIST_HEAD(&hl->hard_links);
++ }
++ }
++}
++
++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
++{
++ /*
++ * Sort out state of unlinked and deleted objects after scanning.
++ */
++ struct list_head *i;
++ struct list_head *n;
++ struct yaffs_obj *l;
++
++ if (dev->read_only)
++ return;
++
++ /* Soft delete all the unlinked files */
++ list_for_each_safe(i, n,
++ &dev->unlinked_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++
++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ * This code assumes that we don't ever change the current relationships
++ * between directories:
++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
++ * lost-n-found->parent == root_dir
++ *
++ * This fixes the problem where directories might have inadvertently been
++ * deleted leaving the object "hanging" without being rooted in the
++ * directory tree.
++ */
++
++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++ return (obj == dev->del_dir ||
++ obj == dev->unlinked_dir || obj == dev->root_dir);
++}
++
++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_obj *parent;
++ int i;
++ struct list_head *lh;
++ struct list_head *n;
++ int depth_limit;
++ int hanging;
++
++ if (dev->read_only)
++ return;
++
++ /* Iterate through the objects in each hash entry,
++ * looking at each object.
++ * Make sure it is rooted.
++ */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ parent = obj->parent;
++
++ if (yaffs_has_null_parent(dev, obj)) {
++ /* These directories are not hanging */
++ hanging = 0;
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ hanging = 1;
++ } else if (yaffs_has_null_parent(dev, parent)) {
++ hanging = 0;
++ } else {
++ /*
++ * Need to follow the parent chain to
++ * see if it is hanging.
++ */
++ hanging = 0;
++ depth_limit = 100;
++
++ while (parent != dev->root_dir &&
++ parent->parent &&
++ parent->parent->variant_type ==
++ YAFFS_OBJECT_TYPE_DIRECTORY &&
++ depth_limit > 0) {
++ parent = parent->parent;
++ depth_limit--;
++ }
++ if (parent != dev->root_dir)
++ hanging = 1;
++ }
++ if (hanging) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Hanging object %d moved to lost and found",
++ obj->obj_id);
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++ }
++ }
++ }
++}
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_del_dir_contents(struct yaffs_obj *dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ BUG();
++
++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
++ yaffs_del_dir_contents(obj);
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Deleting lost_found object %d",
++ obj->obj_id);
++ yaffs_unlink_obj(obj);
++ }
++}
++
++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
++{
++ yaffs_del_dir_contents(dev->lost_n_found);
++}
++
++
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
++ const YCHAR *name)
++{
++ int sum;
++ struct list_head *i;
++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj *l;
++
++ if (!name)
++ return NULL;
++
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: null pointer directory"
++ );
++ BUG();
++ return NULL;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: non-directory"
++ );
++ BUG();
++ }
++
++ sum = yaffs_calc_name_sum(name);
++
++ list_for_each(i, &directory->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++
++ if (l->parent != directory)
++ BUG();
++
++ yaffs_check_obj_details_loaded(l);
++
++ /* Special case for lost-n-found */
++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
++ return l;
++ } else if (l->sum == sum || l->hdr_chunk <= 0) {
++ /* LostnFound chunk called Objxxx
++ * Do a real check
++ */
++ yaffs_get_obj_name(l, buffer,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
++ return l;
++ }
++ }
++ return NULL;
++}
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ obj = obj->variant.hardlink_variant.equiv_obj;
++ yaffs_check_obj_details_loaded(obj);
++ }
++ return obj;
++}
++
++/*
++ * A note or two on object names.
++ * * If the object name is missing, we then make one up in the form objnnn
++ *
++ * * ASCII names are stored in the object header's name field from byte zero
++ * * Unicode names are historically stored starting from byte zero.
++ *
++ * Then there are automatic Unicode names...
++ * The purpose of these is to save names in a way that can be read as
++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
++ * system to share files.
++ *
++ * These automatic unicode are stored slightly differently...
++ * - If the name can fit in the ASCII character space then they are saved as
++ * ascii names as per above.
++ * - If the name needs Unicode then the name is saved in Unicode
++ * starting at oh->name[1].
++
++ */
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size)
++{
++ /* Create an object name if we could not find one. */
++ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
++ YCHAR local_name[20];
++ YCHAR num_string[20];
++ YCHAR *x = &num_string[19];
++ unsigned v = obj->obj_id;
++ num_string[19] = 0;
++ while (v > 0) {
++ x--;
++ *x = '0' + (v % 10);
++ v /= 10;
++ }
++ /* make up a name */
++ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
++ strcat(local_name, x);
++ strncpy(name, local_name, buffer_size - 1);
++ }
++}
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
++{
++ memset(name, 0, buffer_size * sizeof(YCHAR));
++ yaffs_check_obj_details_loaded(obj);
++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
++ } else if (obj->short_name[0]) {
++ strcpy(name, obj->short_name);
++ } else if (obj->hdr_chunk > 0) {
++ int result;
++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
++
++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
++
++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
++
++ if (obj->hdr_chunk > 0) {
++ result = yaffs_rd_chunk_tags_nand(obj->my_dev,
++ obj->hdr_chunk,
++ buffer, NULL);
++ }
++ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
++ buffer_size);
++
++ yaffs_release_temp_buffer(obj->my_dev, buffer);
++ }
++
++ yaffs_fix_null_name(obj, name, buffer_size);
++
++ return strnlen(name, YAFFS_MAX_NAME_LENGTH);
++}
++
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
++{
++ /* Dereference any hard linking */
++ obj = yaffs_get_equivalent_obj(obj);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ return obj->variant.file_variant.file_size;
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ if (!obj->variant.symlink_variant.alias)
++ return 0;
++ return strnlen(obj->variant.symlink_variant.alias,
++ YAFFS_MAX_ALIAS_LENGTH);
++ } else {
++ /* Only a directory should drop through to here */
++ return obj->my_dev->data_bytes_per_chunk;
++ }
++}
++
++int yaffs_get_obj_link_count(struct yaffs_obj *obj)
++{
++ int count = 0;
++ struct list_head *i;
++
++ if (!obj->unlinked)
++ count++; /* the object itself */
++
++ list_for_each(i, &obj->hard_links)
++ count++; /* add the hard links; */
++
++ return count;
++}
++
++int yaffs_get_obj_inode(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ return obj->obj_id;
++}
++
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return DT_DIR;
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return DT_LNK;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ if (S_ISFIFO(obj->yst_mode))
++ return DT_FIFO;
++ if (S_ISCHR(obj->yst_mode))
++ return DT_CHR;
++ if (S_ISBLK(obj->yst_mode))
++ return DT_BLK;
++ if (S_ISSOCK(obj->yst_mode))
++ return DT_SOCK;
++ return DT_REG;
++ break;
++ default:
++ return DT_REG;
++ break;
++ }
++}
++
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
++ return yaffs_clone_str(obj->variant.symlink_variant.alias);
++ else
++ return yaffs_clone_str(_Y(""));
++}
++
++/*--------------------------- Initialisation code -------------------------- */
++
++static int yaffs_check_dev_fns(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++ struct yaffs_tags_handler *tagger = &dev->tagger;
++
++ /* Common functions, gotta have */
++ if (!drv->drv_read_chunk_fn ||
++ !drv->drv_write_chunk_fn ||
++ !drv->drv_erase_fn)
++ return 0;
++
++ if (dev->param.is_yaffs2 &&
++ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
++ return 0;
++
++ /* Install the default tags marshalling functions if needed. */
++ yaffs_tags_compat_install(dev);
++ yaffs_tags_marshall_install(dev);
++
++ /* Check we now have the marshalling functions required. */
++ if (!tagger->write_chunk_tags_fn ||
++ !tagger->read_chunk_tags_fn ||
++ !tagger->query_block_fn ||
++ !tagger->mark_bad_fn)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs_create_initial_dir(struct yaffs_dev *dev)
++{
++ /* Initialise the unlinked, deleted, root and lost+found directories */
++ dev->lost_n_found = dev->root_dir = NULL;
++ dev->unlinked_dir = dev->del_dir = NULL;
++ dev->unlinked_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++ dev->del_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++ dev->root_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
++ YAFFS_ROOT_MODE | S_IFDIR);
++ dev->lost_n_found =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
++ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
++ && dev->del_dir) {
++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++/* Low level init.
++ * Typically only used by yaffs_guts_initialise, but also used by the
++ * Low level yaffs driver tests.
++ */
++
++int yaffs_guts_ll_init(struct yaffs_dev *dev)
++{
++
++
++ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
++
++ if (!dev) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Need a device"
++ );
++ return YAFFS_FAIL;
++ }
++
++ if (dev->ll_init)
++ return YAFFS_OK;
++
++ dev->internal_start_block = dev->param.start_block;
++ dev->internal_end_block = dev->param.end_block;
++ dev->block_offset = 0;
++ dev->chunk_offset = 0;
++ dev->n_free_chunks = 0;
++
++ dev->gc_block = 0;
++
++ if (dev->param.start_block == 0) {
++ dev->internal_start_block = dev->param.start_block + 1;
++ dev->internal_end_block = dev->param.end_block + 1;
++ dev->block_offset = 1;
++ dev->chunk_offset = dev->param.chunks_per_block;
++ }
++
++ /* Check geometry parameters. */
++
++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 1024) ||
++ (!dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 512) ||
++ (dev->param.inband_tags && !dev->param.is_yaffs2) ||
++ dev->param.chunks_per_block < 2 ||
++ dev->param.n_reserved_blocks < 2 ||
++ dev->internal_start_block <= 0 ||
++ dev->internal_end_block <= 0 ||
++ dev->internal_end_block <=
++ (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
++ ) {
++ /* otherwise it is too small */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
++ dev->param.total_bytes_per_chunk,
++ dev->param.is_yaffs2 ? "2" : "",
++ dev->param.inband_tags);
++ return YAFFS_FAIL;
++ }
++
++ /* Sort out space for inband tags, if required */
++ if (dev->param.inband_tags)
++ dev->data_bytes_per_chunk =
++ dev->param.total_bytes_per_chunk -
++ sizeof(struct yaffs_packed_tags2_tags_only);
++ else
++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
++
++ /* Got the right mix of functions? */
++ if (!yaffs_check_dev_fns(dev)) {
++ /* Function missing */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "device function(s) missing or wrong");
++
++ return YAFFS_FAIL;
++ }
++
++ if (yaffs_init_nand(dev) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev)
++{
++ int i;
++ enum yaffs_block_state state;
++ u32 dummy;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if(dev->is_mounted)
++ return YAFFS_FAIL;
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ yaffs_query_init_block_state(dev, i, &state, &dummy);
++ if (state != YAFFS_BLOCK_STATE_DEAD)
++ yaffs_erase_block(dev, i);
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_initialise(struct yaffs_dev *dev)
++{
++ int init_failed = 0;
++ unsigned x;
++ int bits;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if (dev->is_mounted) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
++ return YAFFS_FAIL;
++ }
++
++ dev->is_mounted = 1;
++
++ /* OK now calculate a few things for the device */
++
++ /*
++ * Calculate all the chunk size manipulation numbers:
++ */
++ x = dev->data_bytes_per_chunk;
++ /* We always use dev->chunk_shift and dev->chunk_div */
++ dev->chunk_shift = calc_shifts(x);
++ x >>= dev->chunk_shift;
++ dev->chunk_div = x;
++ /* We only use chunk mask if chunk_div is 1 */
++ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
++
++ /*
++ * Calculate chunk_grp_bits.
++ * We need to find the next power of 2 > than internal_end_block
++ */
++
++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
++
++ bits = calc_shifts_ceiling(x);
++
++ /* Set up tnode width if wide tnodes are enabled. */
++ if (!dev->param.wide_tnodes_disabled) {
++ /* bits must be even so that we end up with 32-bit words */
++ if (bits & 1)
++ bits++;
++ if (bits < 16)
++ dev->tnode_width = 16;
++ else
++ dev->tnode_width = bits;
++ } else {
++ dev->tnode_width = 16;
++ }
++
++ dev->tnode_mask = (1 << dev->tnode_width) - 1;
++
++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++ * so if the bitwidth of the
++ * chunk range we're using is greater than 16 we need
++ * to figure out chunk shift and chunk_grp_size
++ */
++
++ if (bits <= dev->tnode_width)
++ dev->chunk_grp_bits = 0;
++ else
++ dev->chunk_grp_bits = bits - dev->tnode_width;
++
++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
++ if (dev->tnode_size < sizeof(struct yaffs_tnode))
++ dev->tnode_size = sizeof(struct yaffs_tnode);
++
++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
++
++ if (dev->param.chunks_per_block < dev->chunk_grp_size) {
++ /* We have a problem because the soft delete won't work if
++ * the chunk group size > chunks per block.
++ * This can be remedied by using larger "virtual blocks".
++ */
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
++
++ return YAFFS_FAIL;
++ }
++
++ /* Finished verifying the device, continue with initialisation */
++
++ /* More device initialisation */
++ dev->all_gcs = 0;
++ dev->passive_gc_count = 0;
++ dev->oldest_dirty_gc_count = 0;
++ dev->bg_gcs = 0;
++ dev->gc_block_finder = 0;
++ dev->buffered_block = -1;
++ dev->doing_buffered_block_rewrite = 0;
++ dev->n_deleted_files = 0;
++ dev->n_bg_deletions = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_ecc_fixed = 0;
++ dev->n_ecc_unfixed = 0;
++ dev->n_tags_ecc_fixed = 0;
++ dev->n_tags_ecc_unfixed = 0;
++ dev->n_erase_failures = 0;
++ dev->n_erased_blocks = 0;
++ dev->gc_disable = 0;
++ dev->has_pending_prioritised_gc = 1;
++ /* Assume the worst for now, will get fixed on first GC */
++ INIT_LIST_HEAD(&dev->dirty_dirs);
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++
++ /* Initialise temporary buffers and caches. */
++ if (!yaffs_init_tmp_buffers(dev))
++ init_failed = 1;
++
++ dev->cache = NULL;
++ dev->gc_cleanup_list = NULL;
++
++ if (!init_failed && dev->param.n_caches > 0) {
++ int i;
++ void *buf;
++ int cache_bytes =
++ dev->param.n_caches * sizeof(struct yaffs_cache);
++
++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
++
++ dev->cache = kmalloc(cache_bytes, GFP_NOFS);
++
++ buf = (u8 *) dev->cache;
++
++ if (dev->cache)
++ memset(dev->cache, 0, cache_bytes);
++
++ for (i = 0; i < dev->param.n_caches && buf; i++) {
++ dev->cache[i].object = NULL;
++ dev->cache[i].last_use = 0;
++ dev->cache[i].dirty = 0;
++ dev->cache[i].data = buf =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ }
++ if (!buf)
++ init_failed = 1;
++
++ dev->cache_last_use = 0;
++ }
++
++ dev->cache_hits = 0;
++
++ if (!init_failed) {
++ dev->gc_cleanup_list =
++ kmalloc(dev->param.chunks_per_block * sizeof(u32),
++ GFP_NOFS);
++ if (!dev->gc_cleanup_list)
++ init_failed = 1;
++ }
++
++ if (dev->param.is_yaffs2)
++ dev->param.use_header_file_size = 1;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && dev->param.is_yaffs2 &&
++ !dev->param.disable_summary &&
++ !yaffs_summary_init(dev))
++ init_failed = 1;
++
++ if (!init_failed) {
++ /* Now scan the flash. */
++ if (dev->param.is_yaffs2) {
++ if (yaffs2_checkpt_restore(dev)) {
++ yaffs_check_obj_details_loaded(dev->root_dir);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT |
++ YAFFS_TRACE_MOUNT,
++ "yaffs: restored from checkpoint"
++ );
++ } else {
++
++ /* Clean up the mess caused by an aborted
++ * checkpoint load then scan backwards.
++ */
++ yaffs_deinit_blocks(dev);
++
++ yaffs_deinit_tnodes_and_objs(dev);
++
++ dev->n_erased_blocks = 0;
++ dev->n_free_chunks = 0;
++ dev->alloc_block = -1;
++ dev->alloc_page = -1;
++ dev->n_deleted_files = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_bg_deletions = 0;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed
++ && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && !yaffs2_scan_backwards(dev))
++ init_failed = 1;
++ }
++ } else if (!yaffs1_scan(dev)) {
++ init_failed = 1;
++ }
++
++ yaffs_strip_deleted_objs(dev);
++ yaffs_fix_hanging_objs(dev);
++ if (dev->param.empty_lost_n_found)
++ yaffs_empty_l_n_f(dev);
++ }
++
++ if (init_failed) {
++ /* Clean up the mess */
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() aborted.");
++
++ yaffs_deinitialise(dev);
++ return YAFFS_FAIL;
++ }
++
++ /* Zero out stats */
++ dev->n_page_reads = 0;
++ dev->n_page_writes = 0;
++ dev->n_erasures = 0;
++ dev->n_gc_copies = 0;
++ dev->n_retried_writes = 0;
++
++ dev->n_retired_blocks = 0;
++
++ yaffs_verify_free_chunks(dev);
++ yaffs_verify_blocks(dev);
++
++ /* Clean up any aborted checkpoint data */
++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() done.");
++ return YAFFS_OK;
++}
++
++void yaffs_deinitialise(struct yaffs_dev *dev)
++{
++ if (dev->is_mounted) {
++ int i;
++
++ yaffs_deinit_blocks(dev);
++ yaffs_deinit_tnodes_and_objs(dev);
++ yaffs_summary_deinit(dev);
++
++ if (dev->param.n_caches > 0 && dev->cache) {
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ kfree(dev->cache[i].data);
++ dev->cache[i].data = NULL;
++ }
++
++ kfree(dev->cache);
++ dev->cache = NULL;
++ }
++
++ kfree(dev->gc_cleanup_list);
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ kfree(dev->temp_buffer[i].buffer);
++
++ dev->is_mounted = 0;
++
++ yaffs_deinit_nand(dev);
++ }
++}
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev)
++{
++ int n_free = 0;
++ int b;
++ struct yaffs_block_info *blk;
++
++ blk = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++ switch (blk->block_state) {
++ case YAFFS_BLOCK_STATE_EMPTY:
++ case YAFFS_BLOCK_STATE_ALLOCATING:
++ case YAFFS_BLOCK_STATE_COLLECTING:
++ case YAFFS_BLOCK_STATE_FULL:
++ n_free +=
++ (dev->param.chunks_per_block - blk->pages_in_use +
++ blk->soft_del_pages);
++ break;
++ default:
++ break;
++ }
++ blk++;
++ }
++ return n_free;
++}
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
++{
++ /* This is what we report to the outside world */
++ int n_free;
++ int n_dirty_caches;
++ int blocks_for_checkpt;
++ int i;
++
++ n_free = dev->n_free_chunks;
++ n_free += dev->n_deleted_files;
++
++ /* Now count and subtract the number of dirty chunks in the cache. */
++
++ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].dirty)
++ n_dirty_caches++;
++ }
++
++ n_free -= n_dirty_caches;
++
++ n_free -=
++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
++
++ /* Now figure checkpoint space and report that... */
++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
++
++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
++
++ if (n_free < 0)
++ n_free = 0;
++
++ return n_free;
++}
++
++
++
++/*
++ * Marshalling functions to get loff_t file sizes into and out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
++{
++ oh->file_size_low = (fsize & 0xFFFFFFFF);
++ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
++}
++
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
++{
++ loff_t retval;
++
++ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
++ retval = (((loff_t) oh->file_size_high) << 32) |
++ (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
++ else
++ retval = (loff_t) oh->file_size_low;
++
++ return retval;
++}
++
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
++{
++ int i;
++ struct yaffs_block_info *bi;
++ int s;
++
++ for(i = 0; i < 10; i++)
++ bs[i] = 0;
++
++ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ bi = yaffs_get_block_info(dev, i);
++ s = bi->block_state;
++ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
++ bs[0]++;
++ else
++ bs[s]++;
++ }
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_guts.h linux-3.12.20/fs/yaffs2/yaffs_guts.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_guts.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,1007 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "yportenv.h"
++
++#define YAFFS_OK 1
++#define YAFFS_FAIL 0
++
++/* Give us a Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xff
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC 0x5941ff53
++
++/*
++ * Tnodes form a tree with the tnodes in "levels"
++ * Levels greater than 0 hold 8 slots which point to other tnodes.
++ * Those at level 0 hold 16 slots which point to chunks in NAND.
++ *
++ * A maximum level of 8 thust supports files of size up to:
++ *
++ * 2^(3*MAX_LEVEL+4)
++ *
++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
++ * a maximum file size of around 512Gbytees with 2k chunks.
++ */
++#define YAFFS_NTNODES_LEVEL0 16
++#define YAFFS_TNODES_LEVEL0_BITS 4
++#define YAFFS_TNODES_LEVEL0_MASK 0xf
++
++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK 0x7
++#define YAFFS_TNODES_MAX_LEVEL 8
++#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
++ YAFFS_TNODES_INTERNAL_BITS * \
++ YAFFS_TNODES_MAX_LEVEL)
++#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
++
++#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
++
++/* Constants for YAFFS1 mode */
++#define YAFFS_BYTES_PER_SPARE 16
++#define YAFFS_BYTES_PER_CHUNK 512
++#define YAFFS_CHUNK_SIZE_SHIFT 9
++#define YAFFS_CHUNKS_PER_BLOCK 32
++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
++
++
++
++#define YAFFS_ALLOCATION_NOBJECTS 100
++#define YAFFS_ALLOCATION_NTNODES 100
++#define YAFFS_ALLOCATION_NLINKS 100
++
++#define YAFFS_NOBJECT_BUCKETS 256
++
++#define YAFFS_OBJECT_SPACE 0x40000
++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
++
++/* Binary data version stamps */
++#define YAFFS_SUMMARY_VERSION 1
++#define YAFFS_CHECKPOINT_VERSION 7
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH 127
++#define YAFFS_MAX_ALIAS_LENGTH 79
++#else
++#define YAFFS_MAX_NAME_LENGTH 255
++#define YAFFS_MAX_ALIAS_LENGTH 159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH 15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT 1
++#define YAFFS_OBJECTID_LOSTNFOUND 2
++#define YAFFS_OBJECTID_UNLINKED 3
++#define YAFFS_OBJECTID_DELETED 4
++
++/* Fake object Id for summary data */
++#define YAFFS_OBJECTID_SUMMARY 0x10
++
++/* Pseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
++
++#define YAFFS_MAX_SHORT_OP_CACHES 20
++
++#define YAFFS_N_TEMP_BUFFERS 6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS (5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
++
++/* ChunkCache is used for short read/write operations.*/
++struct yaffs_cache {
++ struct yaffs_obj *object;
++ int chunk_id;
++ int last_use;
++ int dirty;
++ int n_bytes; /* Only valid if the cache is dirty */
++ int locked; /* Can't push out or flush while locked. */
++ u8 *data;
++};
++
++/* yaffs1 tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
++ * otherwise the structure size will get blown out.
++ */
++
++struct yaffs_tags {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes_lsb:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 n_bytes_msb:2;
++};
++
++union yaffs_tags_union {
++ struct yaffs_tags as_tags;
++ u8 as_bytes[8];
++};
++
++
++/* Stuff used for extended tags in YAFFS2 */
++
++enum yaffs_ecc_result {
++ YAFFS_ECC_RESULT_UNKNOWN,
++ YAFFS_ECC_RESULT_NO_ERROR,
++ YAFFS_ECC_RESULT_FIXED,
++ YAFFS_ECC_RESULT_UNFIXED
++};
++
++enum yaffs_obj_type {
++ YAFFS_OBJECT_TYPE_UNKNOWN,
++ YAFFS_OBJECT_TYPE_FILE,
++ YAFFS_OBJECT_TYPE_SYMLINK,
++ YAFFS_OBJECT_TYPE_DIRECTORY,
++ YAFFS_OBJECT_TYPE_HARDLINK,
++ YAFFS_OBJECT_TYPE_SPECIAL
++};
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++struct yaffs_ext_tags {
++ unsigned chunk_used; /* Status of the chunk: used or unused */
++ unsigned obj_id; /* If 0 this is not used */
++ unsigned chunk_id; /* If 0 this is a header, else a data chunk */
++ unsigned n_bytes; /* Only valid for data chunks */
++
++ /* The following stuff only has meaning when we read */
++ enum yaffs_ecc_result ecc_result;
++ unsigned block_bad;
++
++ /* YAFFS 1 stuff */
++ unsigned is_deleted; /* The chunk is marked deleted */
++ unsigned serial_number; /* Yaffs1 2-bit serial number */
++
++ /* YAFFS2 stuff */
++ unsigned seq_number; /* The sequence number of this block */
++
++ /* Extra info if this is an object header (YAFFS2 only) */
++
++ unsigned extra_available; /* Extra info available if not zero */
++ unsigned extra_parent_id; /* The parent object */
++ unsigned extra_is_shrink; /* Is it a shrink header? */
++ unsigned extra_shadows; /* Does this shadow another object? */
++
++ enum yaffs_obj_type extra_obj_type; /* What object type? */
++
++ loff_t extra_file_size; /* Length if it is a file */
++ unsigned extra_equiv_id; /* Equivalent object for a hard link */
++};
++
++/* Spare structure for YAFFS1 */
++struct yaffs_spare {
++ u8 tb0;
++ u8 tb1;
++ u8 tb2;
++ u8 tb3;
++ u8 page_status; /* set to 0 to delete the chunk */
++ u8 block_status;
++ u8 tb4;
++ u8 tb5;
++ u8 ecc1[3];
++ u8 tb6;
++ u8 tb7;
++ u8 ecc2[3];
++};
++
++/*Special structure for passing through to mtd */
++struct yaffs_nand_spare {
++ struct yaffs_spare spare;
++ int eccres1;
++ int eccres2;
++};
++
++/* Block data in RAM */
++
++enum yaffs_block_state {
++ YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++ YAFFS_BLOCK_STATE_SCANNING,
++ /* Being scanned */
++
++ YAFFS_BLOCK_STATE_NEEDS_SCAN,
++ /* The block might have something on it (ie it is allocating or full,
++ * perhaps empty) but it needs to be scanned to determine its true
++ * state.
++ * This state is only valid during scanning.
++ * NB We tolerate empty because the pre-scanner might be incapable of
++ * deciding
++ * However, if this state is returned on a YAFFS2 device,
++ * then we expect a sequence number
++ */
++
++ YAFFS_BLOCK_STATE_EMPTY,
++ /* This block is empty */
++
++ YAFFS_BLOCK_STATE_ALLOCATING,
++ /* This block is partially allocated.
++ * At least one page holds valid data.
++ * This is the one currently being used for page
++ * allocation. Should never be more than one of these.
++ * If a block is only partially allocated at mount it is treated as
++ * full.
++ */
++
++ YAFFS_BLOCK_STATE_FULL,
++ /* All the pages in this block have been allocated.
++ * If a block was only partially allocated when mounted we treat
++ * it as fully allocated.
++ */
++
++ YAFFS_BLOCK_STATE_DIRTY,
++ /* The block was full and now all chunks have been deleted.
++ * Erase me, reuse me.
++ */
++
++ YAFFS_BLOCK_STATE_CHECKPOINT,
++ /* This block is assigned to holding checkpoint data. */
++
++ YAFFS_BLOCK_STATE_COLLECTING,
++ /* This block is being garbage collected */
++
++ YAFFS_BLOCK_STATE_DEAD
++ /* This block has failed and is not in use */
++};
++
++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++struct yaffs_block_info {
++
++ s32 soft_del_pages:10; /* number of soft deleted pages */
++ s32 pages_in_use:10; /* number of pages in use */
++ u32 block_state:4; /* One of the above block states. */
++ /* NB use unsigned because enum is sometimes
++ * an int */
++ u32 needs_retiring:1; /* Data has failed on this block, */
++ /*need to get valid data off and retire*/
++ u32 skip_erased_check:1;/* Skip the erased check on this block */
++ u32 gc_prioritise:1; /* An ECC check or blank check has failed.
++ Block should be prioritised for GC */
++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc
++ failures on this block and tried to reuse it */
++ u32 has_summary:1; /* The block has a summary */
++
++ u32 has_shrink_hdr:1; /* This block has at least one shrink header */
++ u32 seq_number; /* block sequence number for yaffs2 */
++
++};
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++struct yaffs_obj_hdr {
++ enum yaffs_obj_type type;
++
++ /* Apply to everything */
++ int parent_obj_id;
++ u16 sum_no_longer_used; /* checksum of name. No longer used */
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ /* The following apply to all object types except for hard links */
++ u32 yst_mode; /* protection */
++
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++
++ /* File size applies to files only */
++ u32 file_size_low;
++
++ /* Equivalent object id applies to hard links only. */
++ int equiv_id;
++
++ /* Alias is for symlinks only. */
++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++ u32 yst_rdev; /* stuff for block and char devices (major/min) */
++
++ u32 win_ctime[2];
++ u32 win_atime[2];
++ u32 win_mtime[2];
++
++ u32 inband_shadowed_obj_id;
++ u32 inband_is_shrink;
++
++ u32 file_size_high;
++ u32 reserved[1];
++ int shadows_obj; /* This object header shadows the
++ specified object if > 0 */
++
++ /* is_shrink applies to object headers written when wemake a hole. */
++ u32 is_shrink;
++
++};
++
++/*--------------------------- Tnode -------------------------- */
++
++struct yaffs_tnode {
++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
++};
++
++/*------------------------ Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++struct yaffs_file_var {
++ loff_t file_size;
++ loff_t scanned_size;
++ loff_t shrink_size;
++ int top_level;
++ struct yaffs_tnode *top;
++};
++
++struct yaffs_dir_var {
++ struct list_head children; /* list of child links */
++ struct list_head dirty; /* Entry for list of dirty directories */
++};
++
++struct yaffs_symlink_var {
++ YCHAR *alias;
++};
++
++struct yaffs_hardlink_var {
++ struct yaffs_obj *equiv_obj;
++ u32 equiv_id;
++};
++
++union yaffs_obj_var {
++ struct yaffs_file_var file_variant;
++ struct yaffs_dir_var dir_variant;
++ struct yaffs_symlink_var symlink_variant;
++ struct yaffs_hardlink_var hardlink_variant;
++};
++
++struct yaffs_obj {
++ u8 deleted:1; /* This should only apply to unlinked files. */
++ u8 soft_del:1; /* it has also been soft deleted */
++ u8 unlinked:1; /* An unlinked file.*/
++ u8 fake:1; /* A fake object has no presence on NAND. */
++ u8 rename_allowed:1; /* Some objects cannot be renamed. */
++ u8 unlink_allowed:1;
++ u8 dirty:1; /* the object needs to be written to flash */
++ u8 valid:1; /* When the file system is being loaded up, this
++ * object might be created before the data
++ * is available
++ * ie. file data chunks encountered before
++ * the header.
++ */
++ u8 lazy_loaded:1; /* This object has been lazy loaded and
++ * is missing some detail */
++
++ u8 defered_free:1; /* Object is removed from NAND, but is
++ * still in the inode cache.
++ * Free of object is defered.
++ * until the inode is released.
++ */
++ u8 being_created:1; /* This object is still being created
++ * so skip some verification checks. */
++ u8 is_shadowed:1; /* This object is shadowed on the way
++ * to being renamed. */
++
++ u8 xattr_known:1; /* We know if this has object has xattribs
++ * or not. */
++ u8 has_xattr:1; /* This object has xattribs.
++ * Only valid if xattr_known. */
++
++ u8 serial; /* serial number of chunk in NAND.*/
++ u16 sum; /* sum of the name to speed searching */
++
++ struct yaffs_dev *my_dev; /* The device I'm on */
++
++ struct list_head hash_link; /* list of objects in hash bucket */
++
++ struct list_head hard_links; /* hard linked object chain*/
++
++ /* directory structure stuff */
++ /* also used for linking up the free list */
++ struct yaffs_obj *parent;
++ struct list_head siblings;
++
++ /* Where's my object header in NAND? */
++ int hdr_chunk;
++
++ int n_data_chunks; /* Number of data chunks for this file. */
++
++ u32 obj_id; /* the object id value */
++
++ u32 yst_mode;
++
++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
++
++#ifdef CONFIG_YAFFS_WINCE
++ u32 win_ctime[2];
++ u32 win_mtime[2];
++ u32 win_atime[2];
++#else
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++#endif
++
++ u32 yst_rdev;
++
++ void *my_inode;
++
++ enum yaffs_obj_type variant_type;
++
++ union yaffs_obj_var variant;
++
++};
++
++struct yaffs_obj_bucket {
++ struct list_head list;
++ int count;
++};
++
++/* yaffs_checkpt_obj holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++struct yaffs_checkpt_obj {
++ int struct_type;
++ u32 obj_id;
++ u32 parent_id;
++ int hdr_chunk;
++ enum yaffs_obj_type variant_type:3;
++ u8 deleted:1;
++ u8 soft_del:1;
++ u8 unlinked:1;
++ u8 fake:1;
++ u8 rename_allowed:1;
++ u8 unlink_allowed:1;
++ u8 serial;
++ int n_data_chunks;
++ loff_t size_or_equiv_obj;
++};
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few.
++ */
++
++struct yaffs_buffer {
++ u8 *buffer;
++ int in_use;
++};
++
++/*----------------- Device ---------------------------------*/
++
++struct yaffs_param {
++ const YCHAR *name;
++
++ /*
++ * Entry parameters set up way early. Yaffs sets up the rest.
++ * The structure should be zeroed out before use so that unused
++ * and default values are zero.
++ */
++
++ int inband_tags; /* Use unband tags */
++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
++ be a power of 2 */
++ int chunks_per_block; /* does not need to be a power of 2 */
++ int spare_bytes_per_chunk; /* spare area size */
++ int start_block; /* Start block we're allowed to use */
++ int end_block; /* End block we're allowed to use */
++ int n_reserved_blocks; /* Tuneable so that we can reduce
++ * reserved blocks on NOR and RAM. */
++
++ int n_caches; /* If <= 0, then short op caching is disabled,
++ * else the number of short op caches.
++ */
++ int cache_bypass_aligned; /* If non-zero then bypass the cache for
++ * aligned writes.
++ */
++
++ int use_nand_ecc; /* Flag to decide whether or not to use
++ * NAND driver ECC on data (yaffs1) */
++ int tags_9bytes; /* Use 9 byte tags */
++ int no_tags_ecc; /* Flag to decide whether or not to do ECC
++ * on packed tags (yaffs2) */
++
++ int is_yaffs2; /* Use yaffs2 mode on this device */
++
++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
++
++ int refresh_period; /* How often to check for a block refresh */
++
++ /* Checkpoint control. Can be set before or after initialisation */
++ u8 skip_checkpt_rd;
++ u8 skip_checkpt_wr;
++
++ int enable_xattr; /* Enable xattribs */
++
++ int max_objects; /*
++ * Set to limit the number of objects created.
++ * 0 = no limit.
++ */
++
++ /* The remove_obj_fn function must be supplied by OS flavours that
++ * need it.
++ * yaffs direct uses it to implement the faster readdir.
++ * Linux uses it to protect the directory during unlocking.
++ */
++ void (*remove_obj_fn) (struct yaffs_obj *obj);
++
++ /* Callback to mark the superblock dirty */
++ void (*sb_dirty_fn) (struct yaffs_dev *dev);
++
++ /* Callback to control garbage collection. */
++ unsigned (*gc_control_fn) (struct yaffs_dev *dev);
++
++ /* Debug control flags. Don't use unless you know what you're doing */
++ int use_header_file_size; /* Flag to determine if we should use
++ * file sizes from the header */
++ int disable_lazy_load; /* Disable lazy loading on this device */
++ int wide_tnodes_disabled; /* Set to disable wide tnodes */
++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of
++ * softdeletion. */
++
++ int defered_dir_update; /* Set to defer directory updates */
++
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ int auto_unicode;
++#endif
++ int always_check_erased; /* Force chunk erased check always on */
++
++ int disable_summary;
++ int disable_bad_block_marking;
++
++};
++
++struct yaffs_driver {
++ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len);
++ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result);
++ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_initialise_fn) (struct yaffs_dev *dev);
++ int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
++};
++
++struct yaffs_tags_handler {
++ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags);
++ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags);
++
++ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++};
++
++struct yaffs_dev {
++ struct yaffs_param param;
++ struct yaffs_driver drv;
++ struct yaffs_tags_handler tagger;
++
++ /* Context storage. Holds extra OS specific data for this device */
++
++ void *os_context;
++ void *driver_context;
++
++ struct list_head dev_list;
++
++ int ll_init;
++ /* Runtime parameters. Set up by YAFFS. */
++ int data_bytes_per_chunk;
++
++ /* Non-wide tnode stuff */
++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
++ * the tnodes are not wide enough.
++ */
++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
++
++ /* Stuff to support wide tnodes */
++ u32 tnode_width;
++ u32 tnode_mask;
++ u32 tnode_size;
++
++ /* Stuff for figuring out file offset to chunk conversions */
++ u32 chunk_shift; /* Shift value */
++ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
++ u32 chunk_mask; /* Mask to use for power-of-2 case */
++
++ int is_mounted;
++ int read_only;
++ int is_checkpointed;
++
++ /* Stuff to support block offsetting to support start block zero */
++ int internal_start_block;
++ int internal_end_block;
++ int block_offset;
++ int chunk_offset;
++
++ /* Runtime checkpointing stuff */
++ int checkpt_page_seq; /* running sequence number of checkpt pages */
++ int checkpt_byte_count;
++ int checkpt_byte_offs;
++ u8 *checkpt_buffer;
++ int checkpt_open_write;
++ int blocks_in_checkpt;
++ int checkpt_cur_chunk;
++ int checkpt_cur_block;
++ int checkpt_next_block;
++ int *checkpt_block_list;
++ int checkpt_max_blocks;
++ u32 checkpt_sum;
++ u32 checkpt_xor;
++
++ int checkpoint_blocks_required; /* Number of blocks needed to store
++ * current checkpoint set */
++
++ /* Block Info */
++ struct yaffs_block_info *block_info;
++ u8 *chunk_bits; /* bitmap of chunks in use */
++ u8 block_info_alt:1; /* allocated using alternative alloc */
++ u8 chunk_bits_alt:1; /* allocated using alternative alloc */
++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
++ * Must be consistent with chunks_per_block.
++ */
++
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int alloc_block_finder; /* Used to search for next allocation block */
++
++ /* Object and Tnode memory management */
++ void *allocator;
++ int n_obj;
++ int n_tnodes;
++
++ int n_hardlinks;
++
++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
++ u32 bucket_finder;
++
++ int n_free_chunks;
++
++ /* Garbage collection control */
++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
++ u32 n_clean_ups;
++
++ unsigned has_pending_prioritised_gc; /* We think this device might
++ have pending prioritised gcs */
++ unsigned gc_disable;
++ unsigned gc_block_finder;
++ unsigned gc_dirtiest;
++ unsigned gc_pages_in_use;
++ unsigned gc_not_done;
++ unsigned gc_block;
++ unsigned gc_chunk;
++ unsigned gc_skip;
++ struct yaffs_summary_tags *gc_sum_tags;
++
++ /* Special directories */
++ struct yaffs_obj *root_dir;
++ struct yaffs_obj *lost_n_found;
++
++ int buffered_block; /* Which block is buffered here? */
++ int doing_buffered_block_rewrite;
++
++ struct yaffs_cache *cache;
++ int cache_last_use;
++
++ /* Stuff for background deletion and unlinked files. */
++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
++ files live. */
++ struct yaffs_obj *del_dir; /* Directory where deleted objects are
++ sent to disappear. */
++ struct yaffs_obj *unlinked_deletion; /* Current file being
++ background deleted. */
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* Temporary buffer management */
++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
++ int max_temp;
++ int temp_in_use;
++ int unmanaged_buffer_allocs;
++ int unmanaged_buffer_deallocs;
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ allocating block */
++ unsigned oldest_dirty_seq;
++ unsigned oldest_dirty_block;
++
++ /* Block refreshing */
++ int refresh_skip; /* A skip down counter.
++ * Refresh happens when this gets to zero. */
++
++ /* Dirty directory handling */
++ struct list_head dirty_dirs; /* List of dirty directories */
++
++ /* Summary */
++ int chunks_per_summary;
++ struct yaffs_summary_tags *sum_tags;
++
++ /* Statistics */
++ u32 n_page_writes;
++ u32 n_page_reads;
++ u32 n_erasures;
++ u32 n_bad_queries;
++ u32 n_bad_markings;
++ u32 n_erase_failures;
++ u32 n_gc_copies;
++ u32 all_gcs;
++ u32 passive_gc_count;
++ u32 oldest_dirty_gc_count;
++ u32 n_gc_blocks;
++ u32 bg_gcs;
++ u32 n_retried_writes;
++ u32 n_retired_blocks;
++ u32 n_ecc_fixed;
++ u32 n_ecc_unfixed;
++ u32 n_tags_ecc_fixed;
++ u32 n_tags_ecc_unfixed;
++ u32 n_deletions;
++ u32 n_unmarked_deletions;
++ u32 refresh_count;
++ u32 cache_hits;
++ u32 tags_used;
++ u32 summary_used;
++
++};
++
++/* The CheckpointDevice structure holds the device information that changes
++ *at runtime and must be preserved over unmount/mount cycles.
++ */
++struct yaffs_checkpt_dev {
++ int struct_type;
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int n_free_chunks;
++
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ * allocating block */
++
++};
++
++struct yaffs_checkpt_validity {
++ int struct_type;
++ u32 magic;
++ u32 version;
++ u32 head;
++};
++
++struct yaffs_shadow_fixer {
++ int obj_id;
++ int shadowed_id;
++ struct yaffs_shadow_fixer *next;
++};
++
++/* Structure for doing xattr modifications */
++struct yaffs_xattr_mod {
++ int set; /* If 0 then this is a deletion */
++ const YCHAR *name;
++ const void *data;
++ int size;
++ int flags;
++ int result;
++};
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_guts_initialise(struct yaffs_dev *dev);
++void yaffs_deinitialise(struct yaffs_dev *dev);
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++ struct yaffs_obj *new_dir, const YCHAR * new_name);
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
++int yaffs_del_obj(struct yaffs_obj *obj);
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type);
++
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
++int yaffs_get_obj_inode(struct yaffs_obj *obj);
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
++int yaffs_get_obj_link_count(struct yaffs_obj *obj);
++
++/* File operations */
++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
++ int n_bytes);
++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid);
++
++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
++
++/* Flushing and checkpointing */
++void yaffs_flush_whole_cache(struct yaffs_dev *dev);
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev);
++int yaffs_checkpoint_restore(struct yaffs_dev *dev);
++
++/* Directory operations */
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid);
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
++ const YCHAR *name);
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
++
++/* Link operations */
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
++ struct yaffs_obj *equiv_obj);
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
++
++/* Symlink operations */
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias);
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev);
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
++ const void *value, int size, int flags);
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
++ int size);
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
++
++/* Special directories */
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj);
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
++
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
++
++/* Debug dump */
++int yaffs_dump_obj(struct yaffs_obj *obj);
++
++void yaffs_guts_test(struct yaffs_dev *dev);
++int yaffs_guts_ll_init(struct yaffs_dev *dev);
++
++
++/* A few useful functions to be used within the core files*/
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn);
++int yaffs_check_ff(u8 *buffer, int n_bytes);
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type);
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan);
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh);
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
++YCHAR *yaffs_clone_str(const YCHAR *str);
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
++ int force, int is_shrink, int shadows,
++ struct yaffs_xattr_mod *xop);
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning);
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn);
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id);
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos);
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev);
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out);
++/*
++ * Marshalling functions to get loff_t file sizes into aand out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
++loff_t yaffs_max_file_size(struct yaffs_dev *dev);
++
++/*
++ * Debug function to count number of blocks in each state
++ * NB Needs to be called with correct number of integers
++ */
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_linux.h linux-3.12.20/fs/yaffs2/yaffs_linux.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_linux.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_LINUX_H__
++#define __YAFFS_LINUX_H__
++
++#include "yportenv.h"
++
++struct yaffs_linux_context {
++ struct list_head context_list; /* List of these we have mounted */
++ struct yaffs_dev *dev;
++ struct super_block *super;
++ struct task_struct *bg_thread; /* Background thread for this device */
++ int bg_running;
++ struct mutex gross_lock; /* Gross locking mutex*/
++ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
++ * at compile time so we have to allocate it.
++ */
++ struct list_head search_contexts;
++ struct task_struct *readdir_process;
++ unsigned mount_id;
++ int dirty;
++};
++
++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
++
++#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
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_mtdif.c linux-3.12.20/fs/yaffs2/yaffs_mtdif.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_mtdif.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,309 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/major.h"
++#include "linux/mtd/nand.h"
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_linux.h"
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++#define mtd_erase(m, ei) (m)->erase(m, ei)
++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
++#endif
++
++
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ u32 addr =
++ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ struct erase_info ei;
++ int retval = 0;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++
++static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
++ dev, nand_chunk, data, data_len, oob, oob_len);
++
++ if (!data || !data_len) {
++ data = NULL;
++ data_len = 0;
++ }
++
++ if (!oob || !oob_len) {
++ oob = NULL;
++ oob_len = 0;
++ }
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = (u8 *)data;
++ ops.oobbuf = (u8 *)oob;
++
++ retval = mtd_write_oob(mtd, addr, &ops);
++ if (retval) {
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "write_oob failed, chunk %d, mtd error %d",
++ nand_chunk, retval);
++ }
++ return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = data;
++ ops.oobbuf = oob;
++
++#if (MTD_VERSION_CODE < MTD_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",
++ nand_chunk, retval);
++
++ switch (retval) {
++ case 0:
++ /* no error */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++
++ case -EUCLEAN:
++ /* MTD's ECC fixed the data */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ break;
++
++ case -EBADMSG:
++ default:
++ /* MTD's ECC could not fix the data */
++ dev->n_ecc_unfixed++;
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ loff_t addr;
++ struct erase_info ei;
++ int retval = 0;
++ u32 block_size;
++
++ block_size = dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ addr = ((loff_t) block_no) * block_size;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = block_size;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
++
++ retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
++
++ retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_initialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++
++ drv->drv_write_chunk_fn = yaffs_mtd_write;
++ drv->drv_read_chunk_fn = yaffs_mtd_read;
++ drv->drv_erase_fn = yaffs_mtd_erase;
++ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
++ drv->drv_check_bad_fn = yaffs_mtd_check_bad;
++ drv->drv_initialise_fn = yaffs_mtd_initialise;
++ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
++}
++
++
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
++{
++ struct mtd_info *mtd;
++
++ mtd = yaffs_get_mtd_device(sdev);
++
++ /* Check it's an mtd device..... */
++ if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
++ return NULL; /* This isn't an mtd device */
++
++ /* Check it's NAND */
++ if (mtd->type != MTD_NANDFLASH) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device is not NAND it's type %d",
++ mtd->type);
++ return NULL;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
++ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
++ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++ yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
++#else
++ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
++#endif
++
++ return mtd;
++}
++
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++{
++ if (yaffs_version == 2) {
++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++ !inband_tags) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not have the right page sizes"
++ );
++ return -1;
++ }
++ } else {
++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not support have the right page sizes"
++ );
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++
++void yaffs_put_mtd_device(struct mtd_info *mtd)
++{
++ if(mtd)
++ put_mtd_device(mtd);
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_mtdif.h linux-3.12.20/fs/yaffs2/yaffs_mtdif.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_mtdif.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev);
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
++void yaffs_put_mtd_device(struct mtd_info *mtd);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_nameval.c linux-3.12.20/fs/yaffs2/yaffs_nameval.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_nameval.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This simple implementation of a name-value store assumes a small number of
++* values and fits into a small finite buffer.
++ *
++ * Each attribute is stored as a record:
++ * sizeof(int) bytes record size.
++ * strnlen+1 bytes name null terminated.
++ * nbytes value.
++ * ----------
++ * total size stored in record size
++ *
++ * This code has not been tested with unicode yet.
++ */
++
++#include "yaffs_nameval.h"
++
++#include "yportenv.h"
++
++static int nval_find(const char *xb, int xb_size, const YCHAR *name,
++ int *exist_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
++ name, size)) {
++ if (exist_size)
++ *exist_size = size;
++ return pos;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ if (exist_size)
++ *exist_size = 0;
++ return -ENODATA;
++}
++
++static int nval_used(const char *xb, int xb_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return pos;
++}
++
++int nval_del(char *xb, int xb_size, const YCHAR *name)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos < 0 || pos >= xb_size)
++ return -ENODATA;
++
++ /* Find size, shift rest over this record,
++ * then zero out the rest of buffer */
++ memcpy(&size, xb + pos, sizeof(int));
++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
++ memset(xb + (xb_size - size), 0, size);
++ return 0;
++}
++
++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
++ int bsize, int flags)
++{
++ int pos;
++ int namelen = strnlen(name, xb_size);
++ int reclen;
++ int size_exist = 0;
++ int space;
++ int start;
++
++ pos = nval_find(xb, xb_size, name, &size_exist);
++
++ if (flags & XATTR_CREATE && pos >= 0)
++ return -EEXIST;
++ if (flags & XATTR_REPLACE && pos < 0)
++ return -ENODATA;
++
++ start = nval_used(xb, xb_size);
++ space = xb_size - start + size_exist;
++
++ reclen = (sizeof(int) + namelen + 1 + bsize);
++
++ if (reclen > space)
++ return -ENOSPC;
++
++ if (pos >= 0) {
++ nval_del(xb, xb_size, name);
++ start = nval_used(xb, xb_size);
++ }
++
++ pos = start;
++
++ memcpy(xb + pos, &reclen, sizeof(int));
++ pos += sizeof(int);
++ strncpy((YCHAR *) (xb + pos), name, reclen);
++ pos += (namelen + 1);
++ memcpy(xb + pos, buf, bsize);
++ return 0;
++}
++
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos >= 0 && pos < xb_size) {
++
++ memcpy(&size, xb + pos, sizeof(int));
++ pos += sizeof(int); /* advance past record length */
++ size -= sizeof(int);
++
++ /* Advance over name string */
++ while (xb[pos] && size > 0 && pos < xb_size) {
++ pos++;
++ size--;
++ }
++ /*Advance over NUL */
++ pos++;
++ size--;
++
++ /* If bsize is zero then this is a size query.
++ * Return the size, but don't copy.
++ */
++ if (!bsize)
++ return size;
++
++ if (size <= bsize) {
++ memcpy(buf, xb + pos, size);
++ return size;
++ }
++ }
++ if (pos >= 0)
++ return -ERANGE;
++
++ return -ENODATA;
++}
++
++int nval_list(const char *xb, int xb_size, char *buf, int bsize)
++{
++ int pos = 0;
++ int size;
++ int name_len;
++ int ncopied = 0;
++ int filled = 0;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > sizeof(int) &&
++ size <= xb_size &&
++ (pos + size) < xb_size &&
++ !filled) {
++ pos += sizeof(int);
++ size -= sizeof(int);
++ name_len = strnlen((YCHAR *) (xb + pos), size);
++ if (ncopied + name_len + 1 < bsize) {
++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
++ buf += name_len;
++ *buf = '\0';
++ buf++;
++ if (sizeof(YCHAR) > 1) {
++ *buf = '\0';
++ buf++;
++ }
++ ncopied += (name_len + 1);
++ } else {
++ filled = 1;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return ncopied;
++}
++
++int nval_hasvalues(const char *xb, int xb_size)
++{
++ return nval_used(xb, xb_size) > 0;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_nameval.h linux-3.12.20/fs/yaffs2/yaffs_nameval.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_nameval.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __NAMEVAL_H__
++#define __NAMEVAL_H__
++
++#include "yportenv.h"
++
++int nval_del(char *xb, int xb_size, const YCHAR * name);
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++ int bsize, int flags);
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize);
++int nval_list(const char *xb, int xb_size, char *buf, int bsize);
++int nval_hasvalues(const char *xb, int xb_size);
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_nand.c linux-3.12.20/fs/yaffs2/yaffs_nand.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_nand.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,122 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++
++#include "yaffs_getblockinfo.h"
++#include "yaffs_summary.h"
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ struct yaffs_ext_tags local_tags;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_reads++;
++
++ /* If there are no tags provided use local tags. */
++ if (!tags)
++ tags = &local_tags;
++
++ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
++
++ struct yaffs_block_info *bi;
++ bi = yaffs_get_block_info(dev,
++ nand_chunk /
++ dev->param.chunks_per_block);
++ yaffs_handle_chunk_error(dev, bi);
++ }
++ return result;
++}
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_writes++;
++
++ if (!tags) {
++ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ tags->seq_number = dev->seq_number;
++ tags->chunk_used = 1;
++ yaffs_trace(YAFFS_TRACE_WRITE,
++ "Writing chunk %d tags %d %d",
++ nand_chunk, tags->obj_id, tags->chunk_id);
++
++ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
++ buffer, tags);
++
++ yaffs_summary_add(dev, tags, nand_chunk);
++
++ return result;
++}
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ block_no -= dev->block_offset;
++ dev->n_bad_markings++;
++
++ if (dev->param.disable_bad_block_marking)
++ return YAFFS_OK;
++
++ return dev->tagger.mark_bad_fn(dev, block_no);
++}
++
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ block_no -= dev->block_offset;
++ return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
++}
++
++int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ int result;
++
++ block_no -= dev->block_offset;
++ dev->n_erasures++;
++ result = dev->drv.drv_erase_fn(dev, block_no);
++ return result;
++}
++
++int yaffs_init_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_initialise_fn)
++ return dev->drv.drv_initialise_fn(dev);
++ return YAFFS_OK;
++}
++
++int yaffs_deinit_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_deinitialise_fn)
++ return dev->drv.drv_deinitialise_fn(dev);
++ return YAFFS_OK;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_nand.h linux-3.12.20/fs/yaffs2/yaffs_nand.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_nand.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ unsigned *seq_number);
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
++
++int yaffs_init_nand(struct yaffs_dev *dev);
++int yaffs_deinit_nand(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.12.20/fs/yaffs2/yaffs_packedtags1.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_packedtags1.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++static const u8 all_ff[20] = {
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t)
++{
++ pt->chunk_id = t->chunk_id;
++ pt->serial_number = t->serial_number;
++ pt->n_bytes = t->n_bytes;
++ pt->obj_id = t->obj_id;
++ pt->ecc = 0;
++ pt->deleted = (t->is_deleted) ? 0 : 1;
++ pt->unused_stuff = 0;
++ pt->should_be_ff = 0xffffffff;
++}
++
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt)
++{
++
++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
++ t->block_bad = 0;
++ if (pt->should_be_ff != 0xffffffff)
++ t->block_bad = 1;
++ t->chunk_used = 1;
++ t->obj_id = pt->obj_id;
++ t->chunk_id = pt->chunk_id;
++ t->n_bytes = pt->n_bytes;
++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ t->is_deleted = (pt->deleted) ? 0 : 1;
++ t->serial_number = pt->serial_number;
++ } else {
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++ }
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.12.20/fs/yaffs2/yaffs_packedtags1.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_packedtags1.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++struct yaffs_packed_tags1 {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 deleted:1;
++ u32 unused_stuff:1;
++ unsigned should_be_ff;
++
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt);
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.12.20/fs/yaffs2/yaffs_packedtags2.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_packedtags2.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunk_id */
++
++#define EXTRA_HEADER_INFO_FLAG 0x80000000
++#define EXTRA_SHRINK_FLAG 0x40000000
++#define EXTRA_SHADOWS_FLAG 0x20000000
++#define EXTRA_SPARE_FLAGS 0x10000000
++
++#define ALL_EXTRA_FLAGS 0xf0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
++
++static void yaffs_dump_packed_tags2_tags_only(
++ const struct yaffs_packed_tags2_tags_only *ptt)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "packed tags obj %d chunk %d byte %d seq %d",
++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
++}
++
++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
++{
++ yaffs_dump_packed_tags2_tags_only(&pt->t);
++}
++
++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
++ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
++ t->seq_number);
++
++}
++
++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
++{
++ if (t->chunk_id != 0 || !t->extra_available)
++ return 0;
++
++ /* Check if the file size is too long to store */
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
++ (t->extra_file_size >> 31) != 0)
++ return 0;
++ return 1;
++}
++
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
++ const struct yaffs_ext_tags *t)
++{
++ ptt->chunk_id = t->chunk_id;
++ ptt->seq_number = t->seq_number;
++ ptt->n_bytes = t->n_bytes;
++ ptt->obj_id = t->obj_id;
++
++ /* Only store extra tags for object headers.
++ * If it is a file then only store if the file size is short\
++ * enough to fit.
++ */
++ if (yaffs_check_tags_extra_packable(t)) {
++ /* Store the extra header info instead */
++ /* We save the parent object in the chunk_id */
++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
++ if (t->extra_is_shrink)
++ ptt->chunk_id |= EXTRA_SHRINK_FLAG;
++ if (t->extra_shadows)
++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
++
++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ ptt->n_bytes = t->extra_equiv_id;
++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ ptt->n_bytes = (unsigned) t->extra_file_size;
++ else
++ ptt->n_bytes = 0;
++ }
++
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc)
++{
++ yaffs_pack_tags2_tags_only(&pt->t, t);
++
++ if (tags_ecc)
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc);
++}
++
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *ptt)
++{
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++
++ if (ptt->seq_number == 0xffffffff)
++ return;
++
++ t->block_bad = 0;
++ t->chunk_used = 1;
++ t->obj_id = ptt->obj_id;
++ t->chunk_id = ptt->chunk_id;
++ t->n_bytes = ptt->n_bytes;
++ t->is_deleted = 0;
++ t->serial_number = 0;
++ t->seq_number = ptt->seq_number;
++
++ /* Do extra header info stuff */
++ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
++ t->chunk_id = 0;
++ t->n_bytes = 0;
++
++ t->extra_available = 1;
++ t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
++ t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
++ t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
++ t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ t->extra_equiv_id = ptt->n_bytes;
++ else
++ t->extra_file_size = ptt->n_bytes;
++ }
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc)
++{
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ if (pt->t.seq_number != 0xffffffff && tags_ecc) {
++ /* Chunk is in use and we need to do ECC */
++
++ struct yaffs_ecc_other ecc;
++ int result;
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &ecc);
++ result =
++ yaffs_ecc_correct_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc, &ecc);
++ switch (result) {
++ case 0:
++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++ case 1:
++ ecc_result = YAFFS_ECC_RESULT_FIXED;
++ break;
++ case -1:
++ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ break;
++ default:
++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ }
++ }
++ yaffs_unpack_tags2_tags_only(t, &pt->t);
++
++ t->ecc_result = ecc_result;
++
++ yaffs_dump_packed_tags2(pt);
++ yaffs_dump_tags2(t);
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.12.20/fs/yaffs2/yaffs_packedtags2.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_packedtags2.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++struct yaffs_packed_tags2_tags_only {
++ unsigned seq_number;
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++struct yaffs_packed_tags2 {
++ struct yaffs_packed_tags2_tags_only t;
++ struct yaffs_ecc_other ecc;
++};
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc);
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *pt);
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_summary.c linux-3.12.20/fs/yaffs2/yaffs_summary.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_summary.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_summary.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,312 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Summaries write the useful part of the tags for the chunks in a block into an
++ * an array which is written to the last n chunks of the block.
++ * Reading the summaries gives all the tags for the block in one read. Much
++ * faster.
++ *
++ * Chunks holding summaries are marked with tags making it look like
++ * they are part of a fake file.
++ *
++ * The summary could also be used during gc.
++ *
++ */
++
++#include "yaffs_summary.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_bitmap.h"
++
++/*
++ * The summary is built up in an array of summary tags.
++ * This gets written to the last one or two (maybe more) chunks in a block.
++ * A summary header is written as the first part of each chunk of summary data.
++ * The summary header must match or the summary is rejected.
++ */
++
++/* Summary tags don't need the sequence number because that is redundant. */
++struct yaffs_summary_tags {
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++/* Summary header */
++struct yaffs_summary_header {
++ unsigned version; /* Must match current version */
++ unsigned block; /* Must be this block */
++ unsigned seq; /* Must be this sequence number */
++ unsigned sum; /* Just add up all the bytes in the tags */
++};
++
++
++static void yaffs_summary_clear(struct yaffs_dev *dev)
++{
++ if (!dev->sum_tags)
++ return;
++ memset(dev->sum_tags, 0, dev->chunks_per_summary *
++ sizeof(struct yaffs_summary_tags));
++}
++
++
++void yaffs_summary_deinit(struct yaffs_dev *dev)
++{
++ kfree(dev->sum_tags);
++ dev->sum_tags = NULL;
++ kfree(dev->gc_sum_tags);
++ dev->gc_sum_tags = NULL;
++ dev->chunks_per_summary = 0;
++}
++
++int yaffs_summary_init(struct yaffs_dev *dev)
++{
++ int sum_bytes;
++ int chunks_used; /* Number of chunks used by summary */
++ int sum_tags_bytes;
++
++ sum_bytes = dev->param.chunks_per_block *
++ sizeof(struct yaffs_summary_tags);
++
++ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
++ (dev->data_bytes_per_chunk -
++ sizeof(struct yaffs_summary_header));
++
++ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ if (!dev->sum_tags || !dev->gc_sum_tags) {
++ yaffs_summary_deinit(dev);
++ return YAFFS_FAIL;
++ }
++
++ yaffs_summary_clear(dev);
++
++ return YAFFS_OK;
++}
++
++static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
++{
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int i;
++ unsigned sum = 0;
++
++ i = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ while (i > 0) {
++ sum += *sum_buffer;
++ sum_buffer++;
++ i--;
++ }
++
++ return sum;
++}
++
++static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int n_bytes;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ memset(&tags, 0, sizeof(struct yaffs_ext_tags));
++ tags.obj_id = YAFFS_OBJECTID_SUMMARY;
++ tags.chunk_id = 1;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ hdr.version = YAFFS_SUMMARY_VERSION;
++ hdr.block = blk;
++ hdr.seq = bi->seq_number;
++ hdr.sum = yaffs_summary_sum(dev);
++
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ memcpy(buffer, &hdr, sizeof(hdr));
++ memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
++ tags.n_bytes = this_tx + sizeof(hdr);
++ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (result != YAFFS_OK)
++ break;
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ dev->n_free_chunks--;
++
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ tags.chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++
++ if (result == YAFFS_OK)
++ bi->has_summary = 1;
++
++
++ return result;
++}
++
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)st;
++ int n_bytes;
++ int chunk_id;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ int sum_tags_bytes;
++
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = blk * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ chunk_id = 1;
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (tags.chunk_id != chunk_id ||
++ tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
++ tags.chunk_used == 0 ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.n_bytes != (this_tx + sizeof(hdr)))
++ result = YAFFS_FAIL;
++ if (result != YAFFS_OK)
++ break;
++
++ if (st == dev->sum_tags) {
++ /* If we're scanning then update the block info */
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ }
++ memcpy(&hdr, buffer, sizeof(hdr));
++ memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (result == YAFFS_OK) {
++ /* Verify header */
++ if (hdr.version != YAFFS_SUMMARY_VERSION ||
++ hdr.seq != bi->seq_number ||
++ hdr.sum != yaffs_summary_sum(dev))
++ result = YAFFS_FAIL;
++ }
++
++ if (st == dev->sum_tags && result == YAFFS_OK)
++ bi->has_summary = 1;
++
++ return result;
++}
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_nand)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
++ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
++
++ if (!dev->sum_tags)
++ return YAFFS_OK;
++
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ yaffs_pack_tags2_tags_only(&tags_only, tags);
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ sum_tags->chunk_id = tags_only.chunk_id;
++ sum_tags->n_bytes = tags_only.n_bytes;
++ sum_tags->obj_id = tags_only.obj_id;
++
++ if (chunk_in_block == dev->chunks_per_summary - 1) {
++ /* Time to write out the summary */
++ yaffs_summary_write(dev, block_in_nand);
++ yaffs_summary_clear(dev);
++ yaffs_skip_rest_of_block(dev);
++ }
++ }
++ return YAFFS_OK;
++}
++
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ tags_only.chunk_id = sum_tags->chunk_id;
++ tags_only.n_bytes = sum_tags->n_bytes;
++ tags_only.obj_id = sum_tags->obj_id;
++ yaffs_unpack_tags2_tags_only(tags, &tags_only);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int i;
++
++ if (!bi->has_summary)
++ return;
++
++ for (i = dev->chunks_per_summary;
++ i < dev->param.chunks_per_block;
++ i++) {
++ if (yaffs_check_chunk_bit(dev, blk, i)) {
++ yaffs_clear_chunk_bit(dev, blk, i);
++ bi->pages_in_use--;
++ dev->n_free_chunks++;
++ }
++ }
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_summary.h linux-3.12.20/fs/yaffs2/yaffs_summary.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_summary.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_summary.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_SUMMARY_H__
++#define __YAFFS_SUMMARY_H__
++
++#include "yaffs_packedtags2.h"
++
++
++int yaffs_summary_init(struct yaffs_dev *dev);
++void yaffs_summary_deinit(struct yaffs_dev *dev);
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk);
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
++
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.12.20/fs/yaffs2/yaffs_tagscompat.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_tagscompat.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,381 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++
++
++/********** Tags ECC calculations *********/
++
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
++{
++ /* Calculate an ecc */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++ unsigned i, j;
++ unsigned ecc = 0;
++ unsigned bit = 0;
++
++ tags->ecc = 0;
++
++ for (i = 0; i < 8; i++) {
++ for (j = 1; j & 0xff; j <<= 1) {
++ bit++;
++ if (b[i] & j)
++ ecc ^= bit;
++ }
++ }
++ tags->ecc = ecc;
++}
++
++int yaffs_check_tags_ecc(struct yaffs_tags *tags)
++{
++ unsigned ecc = tags->ecc;
++
++ yaffs_calc_tags_ecc(tags);
++
++ ecc ^= tags->ecc;
++
++ if (ecc && ecc <= 64) {
++ /* TODO: Handle the failure better. Retire? */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++
++ ecc--;
++
++ b[ecc / 8] ^= (1 << (ecc & 7));
++
++ /* Now recvalc the ecc */
++ yaffs_calc_tags_ecc(tags);
++
++ return 1; /* recovered error */
++ } else if (ecc) {
++ /* Wierd ecc failure value */
++ /* TODO Need to do somethiong here */
++ return -1; /* unrecovered error */
++ }
++ return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++
++ yaffs_calc_tags_ecc(tags_ptr);
++
++ spare_ptr->tb0 = tu->as_bytes[0];
++ spare_ptr->tb1 = tu->as_bytes[1];
++ spare_ptr->tb2 = tu->as_bytes[2];
++ spare_ptr->tb3 = tu->as_bytes[3];
++ spare_ptr->tb4 = tu->as_bytes[4];
++ spare_ptr->tb5 = tu->as_bytes[5];
++ spare_ptr->tb6 = tu->as_bytes[6];
++ spare_ptr->tb7 = tu->as_bytes[7];
++}
++
++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
++ struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++ int result;
++
++ tu->as_bytes[0] = spare_ptr->tb0;
++ tu->as_bytes[1] = spare_ptr->tb1;
++ tu->as_bytes[2] = spare_ptr->tb2;
++ tu->as_bytes[3] = spare_ptr->tb3;
++ tu->as_bytes[4] = spare_ptr->tb4;
++ tu->as_bytes[5] = spare_ptr->tb5;
++ tu->as_bytes[6] = spare_ptr->tb6;
++ tu->as_bytes[7] = spare_ptr->tb7;
++
++ result = yaffs_check_tags_ecc(tags_ptr);
++ if (result > 0)
++ dev->n_tags_ecc_fixed++;
++ else if (result < 0)
++ dev->n_tags_ecc_unfixed++;
++}
++
++static void yaffs_spare_init(struct yaffs_spare *spare)
++{
++ memset(spare, 0xff, sizeof(struct yaffs_spare));
++}
++
++static int yaffs_wr_nand(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ struct yaffs_spare *spare)
++{
++ int data_size = dev->data_bytes_per_chunk;
++
++ return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, sizeof(*spare));
++}
++
++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data,
++ struct yaffs_spare *spare,
++ enum yaffs_ecc_result *ecc_result,
++ int correct_errors)
++{
++ int ret_val;
++ struct yaffs_spare local_spare;
++ int data_size;
++ int spare_size;
++ int ecc_result1, ecc_result2;
++ u8 calc_ecc[3];
++
++ if (!spare) {
++ /* If we don't have a real spare, then we use a local one. */
++ /* Need this for the calculation of the ecc */
++ spare = &local_spare;
++ }
++ data_size = dev->data_bytes_per_chunk;
++ spare_size = sizeof(struct yaffs_spare);
++
++ if (dev->param.use_nand_ecc)
++ return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, spare_size,
++ ecc_result);
++
++
++ /* Handle the ECC at this level. */
++
++ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *)spare, spare_size,
++ NULL);
++ if (!data || !correct_errors)
++ return ret_val;
++
++ /* Do ECC correction if needed. */
++ yaffs_ecc_calc(data, calc_ecc);
++ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
++ yaffs_ecc_calc(&data[256], calc_ecc);
++ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
++
++ if (ecc_result1 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result1 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result2 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result2 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result1 || ecc_result2) {
++ /* We had a data problem on this page */
++ yaffs_handle_rd_data_error(dev, nand_chunk);
++ }
++
++ if (ecc_result1 < 0 || ecc_result2 < 0)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ else if (ecc_result1 > 0 || ecc_result2 > 0)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ else
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ return ret_val;
++}
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++
++ /* Mark the block for retirement */
++ yaffs_get_block_info(dev, flash_block + dev->block_offset)->
++ needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>>Block %d marked for retirement",
++ flash_block);
++
++ /* TODO:
++ * Just do a garbage collection on the affected block
++ * then retire the block
++ * NB recursion
++ */
++}
++
++static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++
++ yaffs_spare_init(&spare);
++
++ if (ext_tags->is_deleted)
++ spare.page_status = 0;
++ else {
++ tags.obj_id = ext_tags->obj_id;
++ tags.chunk_id = ext_tags->chunk_id;
++
++ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
++ else
++ tags.n_bytes_msb = 3;
++
++ tags.serial_number = ext_tags->serial_number;
++
++ if (!dev->param.use_nand_ecc && data) {
++ yaffs_ecc_calc(data, spare.ecc1);
++ yaffs_ecc_calc(&data[256], spare.ecc2);
++ }
++
++ yaffs_load_tags_to_spare(&spare, &tags);
++ }
++ return yaffs_wr_nand(dev, nand_chunk, data, &spare);
++}
++
++static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ int deleted;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ if (!yaffs_rd_chunk_nand(dev, nand_chunk,
++ data, &spare, &ecc_result, 1))
++ return YAFFS_FAIL;
++
++ /* ext_tags may be NULL */
++ if (!ext_tags)
++ return YAFFS_OK;
++
++ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
++
++ ext_tags->is_deleted = deleted;
++ ext_tags->ecc_result = ecc_result;
++ ext_tags->block_bad = 0; /* We're reading it */
++ /* therefore it is not a bad block */
++ ext_tags->chunk_used =
++ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
++
++ if (ext_tags->chunk_used) {
++ yaffs_get_tags_from_spare(dev, &spare, &tags);
++ ext_tags->obj_id = tags.obj_id;
++ ext_tags->chunk_id = tags.chunk_id;
++ ext_tags->n_bytes = tags.n_bytes_lsb;
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ ext_tags->n_bytes |=
++ (((unsigned)tags.n_bytes_msb) << 10);
++
++ ext_tags->serial_number = tags.serial_number;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_spare spare;
++
++ memset(&spare, 0xff, sizeof(struct yaffs_spare));
++
++ spare.block_status = 'Y';
++
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
++ &spare);
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
++ NULL, &spare);
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ struct yaffs_spare spare0, spare1;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ enum yaffs_ecc_result dummy;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ *seq_number = 0;
++
++ /* Look for bad block markers in the first two chunks */
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
++ NULL, &spare0, &dummy, 0);
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
++ NULL, &spare1, &dummy, 0);
++
++ if (hweight8(spare0.block_status & spare1.block_status) < 7)
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ else
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++
++ return YAFFS_OK;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++ if(dev->param.is_yaffs2)
++ return;
++ if(!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
++ if(!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
++ if(!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++ if(!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.12.20/fs/yaffs2/yaffs_tagscompat.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_tagscompat.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++
++#include "yaffs_guts.h"
++
++#if 0
++
++
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++
++#endif
++
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev);
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
++int yaffs_check_tags_ecc(struct yaffs_tags *tags);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.12.20/fs/yaffs2/yaffs_tagsmarshall.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_tagsmarshall.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,199 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_packedtags2.h"
++
++static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ struct yaffs_packed_tags2 pt;
++ int retval;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_write chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ /* For yaffs2 writing there must be both data and tags.
++ * If we're using inband tags, then the tags are stuffed into
++ * the end of the data buffer.
++ */
++ if (!data || !tags)
++ BUG();
++ else if (dev->param.inband_tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)(data +
++ dev->
++ data_bytes_per_chunk);
++ yaffs_pack_tags2_tags_only(pt2tp, tags);
++ } else {
++ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
++ }
++
++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ (dev->param.inband_tags) ? NULL : packed_tags_ptr,
++ (dev->param.inband_tags) ? 0 : packed_tags_size);
++
++ return retval;
++}
++
++static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = 0;
++ int local_data = 0;
++ u8 spare_buffer[100];
++ enum yaffs_ecc_result ecc_result;
++
++ struct yaffs_packed_tags2 pt;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_read chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ if (dev->param.inband_tags) {
++ if (!data) {
++ local_data = 1;
++ data = yaffs_get_temp_buffer(dev);
++ }
++ }
++
++ if (dev->param.inband_tags || (data && !tags))
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ NULL, 0,
++ &ecc_result);
++ else if (tags)
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ spare_buffer, packed_tags_size,
++ &ecc_result);
++ else
++ BUG();
++
++
++ if (dev->param.inband_tags) {
++ if (tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)
++ &data[dev->data_bytes_per_chunk];
++ yaffs_unpack_tags2_tags_only(tags, pt2tp);
++ }
++ } else if (tags) {
++ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
++ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
++ }
++
++ if (local_data)
++ yaffs_release_temp_buffer(dev, data);
++
++ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ dev->n_ecc_unfixed++;
++ }
++
++ if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
++ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ }
++
++ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
++ block_no);
++
++ retval = dev->drv.drv_check_bad_fn(dev, block_no);
++
++ if (retval== YAFFS_FAIL) {
++ yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
++
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ *seq_number = 0;
++ } else {
++ struct yaffs_ext_tags t;
++
++ yaffs_tags_marshall_read(dev,
++ block_no * dev->param.chunks_per_block,
++ NULL, &t);
++
++ if (t.chunk_used) {
++ *seq_number = t.seq_number;
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++ } else {
++ *seq_number = 0;
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "block query returns seq %d state %d",
++ *seq_number, *state);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ return dev->drv.drv_mark_bad_fn(dev, block_no);
++
++}
++
++
++void yaffs_tags_marshall_install(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
++
++ if (!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
++
++ if (!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
++
++ if (!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
++
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.12.20/fs/yaffs2/yaffs_tagsmarshall.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_tagsmarshall.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSMARSHALL_H__
++#define __YAFFS_TAGSMARSHALL_H__
++
++#include "yaffs_guts.h"
++void yaffs_tags_marshall_install(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_trace.h linux-3.12.20/fs/yaffs2/yaffs_trace.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_trace.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_trace_mask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS 0x00000002
++#define YAFFS_TRACE_ALLOCATE 0x00000004
++#define YAFFS_TRACE_SCAN 0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
++#define YAFFS_TRACE_ERASE 0x00000020
++#define YAFFS_TRACE_GC 0x00000040
++#define YAFFS_TRACE_WRITE 0x00000080
++#define YAFFS_TRACE_TRACING 0x00000100
++#define YAFFS_TRACE_DELETION 0x00000200
++#define YAFFS_TRACE_BUFFERS 0x00000400
++#define YAFFS_TRACE_NANDACCESS 0x00000800
++#define YAFFS_TRACE_GC_DETAIL 0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
++#define YAFFS_TRACE_MTD 0x00004000
++#define YAFFS_TRACE_CHECKPOINT 0x00008000
++
++#define YAFFS_TRACE_VERIFY 0x00010000
++#define YAFFS_TRACE_VERIFY_NAND 0x00020000
++#define YAFFS_TRACE_VERIFY_FULL 0x00040000
++#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
++
++#define YAFFS_TRACE_SYNC 0x00100000
++#define YAFFS_TRACE_BACKGROUND 0x00200000
++#define YAFFS_TRACE_LOCK 0x00400000
++#define YAFFS_TRACE_MOUNT 0x00800000
++
++#define YAFFS_TRACE_ERROR 0x40000000
++#define YAFFS_TRACE_BUG 0x80000000
++#define YAFFS_TRACE_ALWAYS 0xf0000000
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_verify.c linux-3.12.20/fs/yaffs2/yaffs_verify.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_verify.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,529 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_verify.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++
++int yaffs_skip_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask &
++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_full_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char * const block_state_name[] = {
++ "Unknown",
++ "Needs scan",
++ "Scanning",
++ "Empty",
++ "Allocating",
++ "Full",
++ "Dirty",
++ "Checkpoint",
++ "Collecting",
++ "Dead"
++};
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
++{
++ int actually_used;
++ int in_use;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Report illegal runtime states */
++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has undefined state %d",
++ n, bi->block_state);
++
++ switch (bi->block_state) {
++ case YAFFS_BLOCK_STATE_UNKNOWN:
++ case YAFFS_BLOCK_STATE_SCANNING:
++ case YAFFS_BLOCK_STATE_NEEDS_SCAN:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has bad run-state %s",
++ n, block_state_name[bi->block_state]);
++ }
++
++ /* Check pages in use and soft deletions are legal */
++
++ actually_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->pages_in_use < 0 ||
++ bi->pages_in_use > dev->param.chunks_per_block ||
++ bi->soft_del_pages < 0 ||
++ bi->soft_del_pages > dev->param.chunks_per_block ||
++ actually_used < 0 || actually_used > dev->param.chunks_per_block)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has illegal values pages_in_used %d soft_del_pages %d",
++ n, bi->pages_in_use, bi->soft_del_pages);
++
++ /* Check chunk bitmap legal */
++ in_use = yaffs_count_chunk_bits(dev, n);
++ if (in_use != bi->pages_in_use)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
++ n, bi->pages_in_use, in_use);
++}
++
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n)
++{
++ yaffs_verify_blk(dev, bi, n);
++
++ /* After collection the block should be in the erased state */
++
++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Block %d is in state %d after gc, should be erased",
++ n, bi->block_state);
++ }
++}
++
++void yaffs_verify_blocks(struct yaffs_dev *dev)
++{
++ int i;
++ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
++ int illegal_states = 0;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ memset(state_count, 0, sizeof(state_count));
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ yaffs_verify_blk(dev, bi, i);
++
++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
++ state_count[bi->block_state]++;
++ else
++ illegal_states++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
++
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%d blocks have illegal states",
++ illegal_states);
++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many allocating blocks");
++
++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%s %d blocks",
++ block_state_name[i], state_count[i]);
++
++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Checkpoint block count wrong dev %d count %d",
++ dev->blocks_in_checkpt,
++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
++
++ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Erased block count wrong dev %d count %d",
++ dev->n_erased_blocks,
++ state_count[YAFFS_BLOCK_STATE_EMPTY]);
++
++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many collecting blocks %d (max is 1)",
++ state_count[YAFFS_BLOCK_STATE_COLLECTING]);
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in
++ * which case those tests will not be performed.
++ */
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!(tags && obj && oh)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Verifying object header tags %p obj %p oh %p",
++ tags, obj, oh);
++ return;
++ }
++
++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++ oh->type > YAFFS_OBJECT_TYPE_MAX)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header type is illegal value 0x%x",
++ tags->obj_id, oh->type);
++
++ if (tags->obj_id != obj->obj_id)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch obj_id %d",
++ tags->obj_id, obj->obj_id);
++
++ /*
++ * Check that the object's parent ids match if parent_check requested.
++ *
++ * Tests do not apply to the root object.
++ */
++
++ if (parent_check && tags->obj_id > 1 && !obj->parent)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d obj->parent is NULL",
++ tags->obj_id, oh->parent_obj_id);
++
++ if (parent_check && obj->parent &&
++ oh->parent_obj_id != obj->parent->obj_id &&
++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d parent_obj_id %d",
++ tags->obj_id, oh->parent_obj_id,
++ obj->parent->obj_id);
++
++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is NULL",
++ obj->obj_id);
++
++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is 0xff",
++ obj->obj_id);
++}
++
++void yaffs_verify_file(struct yaffs_obj *obj)
++{
++ u32 x;
++ int required_depth;
++ int actual_depth;
++ int last_chunk;
++ u32 offset_in_chunk;
++ u32 the_chunk;
++
++ u32 i;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ struct yaffs_tnode *tn;
++ u32 obj_id;
++
++ if (!obj)
++ return;
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ dev = obj->my_dev;
++ obj_id = obj->obj_id;
++
++
++ /* Check file size is consistent with tnode depth */
++ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
++ &last_chunk, &offset_in_chunk);
++ last_chunk++;
++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x > 0) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ actual_depth = obj->variant.file_variant.top_level;
++
++ /* Check that the chunks in the tnode tree are all correct.
++ * We do this by scanning through the tnode tree and
++ * checking the tags for every chunk match.
++ */
++
++ if (yaffs_skip_nand_verification(dev))
++ return;
++
++ for (i = 1; i <= last_chunk; i++) {
++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
++
++ if (!tn)
++ continue;
++
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk > 0) {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ &tags);
++ if (tags.obj_id != obj_id || tags.chunk_id != i)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
++ obj_id, i, the_chunk,
++ tags.obj_id, tags.chunk_id);
++ }
++ }
++}
++
++void yaffs_verify_link(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify sane equivalent object */
++}
++
++void yaffs_verify_symlink(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify symlink string */
++}
++
++void yaffs_verify_special(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++}
++
++void yaffs_verify_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++ u32 chunk_min;
++ u32 chunk_max;
++ u32 chunk_id_ok;
++ u32 chunk_in_range;
++ u32 chunk_wrongly_deleted;
++ u32 chunk_valid;
++
++ if (!obj)
++ return;
++
++ if (obj->being_created)
++ return;
++
++ dev = obj->my_dev;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Check sane object header chunk */
++
++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
++ chunk_max =
++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
++
++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
++ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
++ chunk_valid = chunk_in_range &&
++ yaffs_check_chunk_bit(dev,
++ obj->hdr_chunk / dev->param.chunks_per_block,
++ obj->hdr_chunk % dev->param.chunks_per_block);
++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
++
++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has chunk_id %d %s %s",
++ obj->obj_id, obj->hdr_chunk,
++ chunk_id_ok ? "" : ",out of range",
++ chunk_wrongly_deleted ? ",marked as deleted" : "");
++
++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj_hdr *oh;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
++
++ yaffs_verify_oh(obj, oh, &tags, 1);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ /* Verify it has a parent */
++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has parent pointer %p which does not look like an object",
++ obj->obj_id, obj->parent);
++ }
++
++ /* Verify parent is a directory */
++ if (obj->parent &&
++ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d's parent is not a directory (type %d)",
++ obj->obj_id, obj->parent->variant_type);
++ }
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ yaffs_verify_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ yaffs_verify_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ yaffs_verify_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ yaffs_verify_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ yaffs_verify_special(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has illegaltype %d",
++ obj->obj_id, obj->variant_type);
++ break;
++ }
++}
++
++void yaffs_verify_objects(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int i;
++ struct list_head *lh;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Iterate through the objects in each hash entry */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ yaffs_verify_obj(obj);
++ }
++ }
++}
++
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++ int count = 0;
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!obj->parent) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
++ BUG();
++ return;
++ }
++
++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_verify_obj(list_obj);
++ if (obj == list_obj)
++ count++;
++ }
++
++ if (count != 1) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory %d times",
++ count);
++ BUG();
++ }
++}
++
++void yaffs_verify_dir(struct yaffs_obj *directory)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++
++ if (!directory) {
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_full_verification(directory->my_dev))
++ return;
++
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Directory has wrong type: %d",
++ directory->variant_type);
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &directory->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (list_obj->parent != directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory list has wrong parent %p",
++ list_obj->parent);
++ BUG();
++ }
++ yaffs_verify_obj_in_dir(list_obj);
++ }
++}
++
++static int yaffs_free_verification_failures;
++
++void yaffs_verify_free_chunks(struct yaffs_dev *dev)
++{
++ int counted;
++ int difference;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ counted = yaffs_count_free_chunks(dev);
++
++ difference = dev->n_free_chunks - counted;
++
++ if (difference) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Freechunks verification failure %d %d %d",
++ dev->n_free_chunks, counted, difference);
++ yaffs_free_verification_failures++;
++ }
++}
++
++int yaffs_verify_file_sane(struct yaffs_obj *in)
++{
++ (void) in;
++ return YAFFS_OK;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_verify.h linux-3.12.20/fs/yaffs2/yaffs_verify.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_verify.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_VERIFY_H__
++#define __YAFFS_VERIFY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
++ int n);
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n);
++void yaffs_verify_blocks(struct yaffs_dev *dev);
++
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check);
++void yaffs_verify_file(struct yaffs_obj *obj);
++void yaffs_verify_link(struct yaffs_obj *obj);
++void yaffs_verify_symlink(struct yaffs_obj *obj);
++void yaffs_verify_special(struct yaffs_obj *obj);
++void yaffs_verify_obj(struct yaffs_obj *obj);
++void yaffs_verify_objects(struct yaffs_dev *dev);
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
++void yaffs_verify_dir(struct yaffs_obj *directory);
++void yaffs_verify_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_verify_file_sane(struct yaffs_obj *obj);
++
++int yaffs_skip_verification(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_vfs.c linux-3.12.20/fs/yaffs2/yaffs_vfs.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_vfs.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,3600 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * 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 struct yaffs_dev associated with
++ * this superblock
++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
++ * superblock
++ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
++ */
++
++/*
++ * There are two variants of the VFS glue code. This variant should compile
++ * for any version of Linux.
++ */
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
++#define YAFFS_COMPILE_BACKGROUND
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
++#define YAFFS_COMPILE_FREEZER
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
++#define YAFFS_COMPILE_EXPORTFS
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_USE_SETATTR_COPY
++#define YAFFS_USE_TRUNCATE_SETSIZE
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_HAS_EVICT_INODE
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++#define YAFFS_NEW_FOLLOW_LINK 1
++#else
++#define YAFFS_NEW_FOLLOW_LINK 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_HAS_WRITE_SUPER
++#endif
++
++
++#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/fs.h>
++#include <linux/proc_fs.h>
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
++#include <linux/smp_lock.h>
++#endif
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++#include <linux/namei.h>
++#endif
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++#include <linux/exportfs.h>
++#endif
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#endif
++#ifdef YAFFS_COMPILE_FREEZER
++#include <linux/freezer.h>
++#endif
++
++#include <asm/div64.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/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, 26))
++#define YPROC_ROOT (&proc_root)
++#else
++#define YPROC_ROOT NULL
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define Y_INIT_TIMER(a) init_timer(a)
++#else
++#define Y_INIT_TIMER(a) init_timer_on_stack(a)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_SUPER_HAS_DIRTY
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++ uint64_t result = partition_size;
++ do_div(result, block_size);
++ return (uint32_t) result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/mtd/mtd.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#include "yaffs_linux.h"
++
++#include "yaffs_mtdif.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_getblockinfo.h"
++
++unsigned int yaffs_trace_mask =
++ YAFFS_TRACE_BAD_BLOCKS |
++ YAFFS_TRACE_ALWAYS |
++ 0;
++
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++unsigned int yaffs_gc_control = 1;
++unsigned int yaffs_bg_enable = 1;
++unsigned int yaffs_auto_select = 1;
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_trace_mask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++module_param(yaffs_gc_control, uint, 0644);
++module_param(yaffs_bg_enable, uint, 0644);
++#else
++MODULE_PARM(yaffs_trace_mask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++MODULE_PARM(yaffs_gc_control, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
++#else
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_inode_to_obj(iptr) \
++ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
++#else
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define Y_CLEAR_INODE(i) clear_inode(i)
++#else
++#define Y_CLEAR_INODE(i) end_writeback(i)
++#endif
++
++
++#define update_dir_time(dir) do {\
++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++ } while (0)
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj);
++
++
++static void yaffs_gross_lock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
++}
++
++static void yaffs_gross_unlock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
++}
++
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++ /* Lifted from jffs2 */
++
++ struct yaffs_obj *obj;
++ unsigned char *pg_buf;
++ int ret;
++ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readpage_nolock at %lld, size %08x",
++ (long long)pos,
++ (unsigned)PAGE_CACHE_SIZE);
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++#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_gross_lock(dev);
++
++ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
++
++ yaffs_gross_unlock(dev);
++
++ if (ret >= 0)
++ ret = 0;
++
++ if (ret) {
++ ClearPageUptodate(pg);
++ SetPageError(pg);
++ } else {
++ SetPageUptodate(pg);
++ ClearPageError(pg);
++ }
++
++ flush_dcache_page(pg);
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
++ 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)
++{
++ int ret;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
++ ret = yaffs_readpage_unlock(f, pg);
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
++ return ret;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
++#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
++#else
++#define YCRED_FSUID() YCRED(current)->fsuid
++#define YCRED_FSGID() YCRED(current)->fsgid
++
++static inline uid_t i_uid_read(const struct inode *inode)
++{
++ return inode->i_uid;
++}
++
++static inline gid_t i_gid_read(const struct inode *inode)
++{
++ return inode->i_gid;
++}
++
++static inline void i_uid_write(struct inode *inode, uid_t uid)
++{
++ inode->i_uid = uid;
++}
++
++static inline void i_gid_write(struct inode *inode, gid_t gid)
++{
++ inode->i_gid = gid;
++}
++#endif
++
++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc)
++ lc->dirty = val;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb)
++ sb->s_dirt = val;
++ }
++#endif
++
++}
++
++static void yaffs_set_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 1);
++}
++
++static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 0);
++}
++
++static int yaffs_check_super_dirty(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc && lc->dirty)
++ return 1;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb && sb->s_dirt)
++ return 1;
++ }
++#endif
++ return 0;
++
++}
++
++#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 yaffs_dev *dev;
++ struct address_space *mapping = page->mapping;
++ struct inode *inode;
++ unsigned long end_index;
++ char *buffer;
++ struct yaffs_obj *obj;
++ int n_written = 0;
++ unsigned n_bytes;
++ loff_t i_size;
++
++ if (!mapping)
++ BUG();
++ inode = mapping->host;
++ if (!inode)
++ BUG();
++ i_size = i_size_read(inode);
++
++ end_index = i_size >> PAGE_CACHE_SHIFT;
++
++ if (page->index < end_index)
++ n_bytes = PAGE_CACHE_SIZE;
++ else {
++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
++
++ if (page->index > end_index || !n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, inode size = %lld!!",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
++ inode->i_size);
++ yaffs_trace(YAFFS_TRACE_OS,
++ " -> don't care!!");
++
++ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ return 0;
++ }
++ }
++
++ if (n_bytes != PAGE_CACHE_SIZE)
++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
++
++ get_page(page);
++
++ buffer = kmap(page);
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, size %08x",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag0: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ n_written = yaffs_wr_file(obj, buffer,
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag1: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ yaffs_gross_unlock(dev);
++
++ kunmap(page);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ put_page(page);
++
++ return (n_written == n_bytes) ? 0 : -ENOSPC;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ int n_free_chunks;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ n_free_chunks = yaffs_get_n_free_chunks(dev);
++
++ yaffs_gross_unlock(dev);
++
++ return (n_free_chunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_gross_unlock(dev);
++}
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{
++ struct page *pg = NULL;
++ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++ int ret = 0;
++ int space_held = 0;
++
++ /* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++ pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++ pg = __grab_cache_page(mapping, index);
++#endif
++
++ *pagep = pg;
++ if (!pg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "start yaffs_write_begin index %d(%x) uptodate %d",
++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
++
++ /* Get fs space */
++ space_held = yaffs_hold_space(filp);
++
++ if (!space_held) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ /* Update page if required */
++
++ if (!Page_Uptodate(pg))
++ ret = yaffs_readpage_nolock(filp, pg);
++
++ if (ret)
++ goto out;
++
++ /* Happy path return */
++ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
++
++ return 0;
++
++out:
++ yaffs_trace(YAFFS_TRACE_OS,
++ "end yaffs_write_begin fail returning %d", ret);
++ if (space_held)
++ yaffs_release_space(filp);
++ if (pg) {
++ unlock_page(pg);
++ page_cache_release(pg);
++ }
++ return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to)
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
++
++ if (!Page_Uptodate(pg))
++ return yaffs_readpage_nolock(f, pg);
++ return 0;
++}
++#endif
++
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t * pos)
++{
++ struct yaffs_obj *obj;
++ int n_written;
++ loff_t ipos;
++ struct inode *inode;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: hey obj is null!");
++ return -EINVAL;
++ }
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
++ (unsigned)n, (unsigned)n, obj->obj_id, ipos);
++
++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: %d(%x) bytes written",
++ (unsigned)n, (unsigned)n);
++
++ if (n_written > 0) {
++ ipos += n_written;
++ *pos = ipos;
++ if (ipos > inode->i_size) {
++ inode->i_size = ipos;
++ inode->i_blocks = (ipos + 511) >> 9;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write size updated to %lld bytes, %d blocks",
++ ipos, (int)(inode->i_blocks));
++ }
++
++ }
++ yaffs_gross_unlock(dev);
++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
++}
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata)
++{
++ int ret = 0;
++ void *addr, *kva;
++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++ kva = kmap(pg);
++ addr = kva + offset_into_page;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end addr %p pos %lld n_bytes %d",
++ addr, pos, copied);
++
++ ret = yaffs_file_write(filp, addr, copied, &pos);
++
++ if (ret != copied) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end not same size ret %d copied %d",
++ ret, copied);
++ SetPageError(pg);
++ }
++
++ kunmap(pg);
++
++ yaffs_release_space(filp);
++ unlock_page(pg);
++ page_cache_release(pg);
++ return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to)
++{
++ void *addr, *kva;
++
++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++ int n_bytes = to - offset;
++ int n_written;
++
++ kva = kmap(pg);
++ addr = kva + offset;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write addr %p pos %lld n_bytes %d",
++ addr, pos, n_bytes);
++
++ n_written = yaffs_file_write(f, addr, n_bytes, &pos);
++
++ if (n_written != n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write not same size n_written %d n_bytes %d",
++ n_written, n_bytes);
++ SetPageError(pg);
++ }
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write returning %d",
++ n_written == n_bytes ? 0 : n_written);
++
++ return n_written == n_bytes ? 0 : n_written;
++}
++#endif
++
++static struct address_space_operations yaffs_file_address_operations = {
++ .readpage = yaffs_readpage,
++ .writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++ .write_begin = yaffs_write_begin,
++ .write_end = yaffs_write_end,
++#else
++ .prepare_write = yaffs_prepare_write,
++ .commit_write = yaffs_commit_write,
++#endif
++};
++
++
++#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
++{
++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_flush object %d (%s)",
++ obj->obj_id,
++ obj->dirty ? "dirty" : "clean");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_file(obj, 1, 0);
++
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync)
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync)
++#endif
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++ struct dentry *dentry = file->f_path.dentry;
++#endif
++
++ obj = yaffs_dentry_to_obj(dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_object");
++ yaffs_gross_lock(dev);
++ yaffs_flush_file(obj, 1, datasync);
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const 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,
++ .llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const 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 const 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
++
++
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++ void *kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + start, 0, end - start);
++ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(page);
++}
++#endif
++
++
++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
++{
++#ifdef YAFFS_USE_TRUNCATE_SETSIZE
++ truncate_setsize(inode, newsize);
++ return 0;
++#else
++ truncate_inode_pages(&inode->i_data, newsize);
++ return 0;
++#endif
++
++}
++
++
++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
++{
++#ifdef YAFFS_USE_SETATTR_COPY
++ setattr_copy(inode, attr);
++ return 0;
++#else
++ return inode_setattr(inode, attr);
++#endif
++
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_setattr of object %d",
++ yaffs_inode_to_obj(inode)->obj_id);
++#if 0
++ /* Fail if a requested resize >= 2GB */
++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
++ error = -EINVAL;
++#endif
++
++ if (error == 0)
++ error = inode_change_ok(inode, attr);
++ if (error == 0) {
++ int result;
++ if (!error) {
++ error = yaffs_vfs_setattr(inode, attr);
++ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_vfs_setsize(inode, attr->ia_size);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++ }
++ }
++ dev = yaffs_inode_to_obj(inode)->my_dev;
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "resize to %d(%x)",
++ (int)(attr->ia_size),
++ (int)(attr->ia_size));
++ }
++ yaffs_gross_lock(dev);
++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
++ if (result == YAFFS_OK) {
++ error = 0;
++ } else {
++ error = -EPERM;
++ }
++ yaffs_gross_unlock(dev);
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_set_xattrib(obj, name, value, size, flags);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
++ void *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_getxattr \"%s\" from object %d",
++ name, obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_get_xattrib(obj, name, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_removexattr(struct dentry *dentry, const char *name)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_remove_xattrib(obj, name);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_list_xattrib(obj, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr done returning %d", error);
++
++ return error;
++}
++
++
++static const struct inode_operations yaffs_file_inode_operations = {
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++ int buflen)
++{
++ unsigned char *alias;
++ int ret;
++
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++
++ yaffs_gross_unlock(dev);
++
++ if (!alias)
++ return -ENOMEM;
++
++ ret = vfs_readlink(dentry, buffer, buflen, alias);
++ kfree(alias);
++ return ret;
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ void *ret;
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int ret
++#endif
++ unsigned char *alias;
++ int ret_int = 0;
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++ yaffs_gross_unlock(dev);
++
++ if (!alias) {
++ ret_int = -ENOMEM;
++ goto out;
++ }
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ nd_set_link(nd, alias);
++ ret = alias;
++out:
++ if (ret_int)
++ ret = ERR_PTR(ret_int);
++ return ret;
++#else
++ ret = vfs_follow_link(nd, alias);
++ kfree(alias);
++out:
++ if (ret_int)
++ ret = ret_int;
++ return ret;
++#endif
++}
++
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* 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)
++{
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_put_inode: ino %d, count %d"),
++ (int)inode->i_ino, atomic_read(&inode->i_count);
++
++}
++#endif
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++{
++ kfree(alias);
++}
++#endif
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++ .readlink = yaffs_readlink,
++ .follow_link = yaffs_follow_link,
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ .put_link = yaffs_put_link,
++#endif
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++ struct inode *inode;
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return 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_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ yaffs_gross_unlock(dev);
++
++ unlock_new_inode(inode);
++ return inode;
++}
++
++#else
++
++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.
++ */
++
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_inode for %d", (int)inode->i_ino);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++}
++
++#endif
++
++
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ struct yaffs_obj *obj)
++{
++ struct inode *inode;
++
++ if (!sb) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL super_block!!");
++ return NULL;
++
++ }
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL object!!");
++ return NULL;
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for object %d", obj->obj_id);
++
++ inode = Y_IGET(sb, obj->obj_id);
++ if (IS_ERR(inode))
++ return NULL;
++
++ /* NB Side effect: iget calls back to yaffs_read_inode(). */
++ /* iget also increments the inode's i_count */
++ /* NB You can't be holding gross_lock or deadlock will happen! */
++
++ return inode;
++}
++
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++ dev_t rdev)
++#elif (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;
++
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_dev *dev;
++
++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
++
++ int error = -ENOSPC;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++ mode |= S_ISGID;
++
++ if (parent) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: parent object %d type %d",
++ parent->obj_id, parent->variant_type);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: could not get parent object");
++ return -EPERM;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: making oject for %s, mode %x dev %x",
++ dentry->d_name.name, mode, rdev);
++
++ dev = parent->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ switch (mode & S_IFMT) {
++ default:
++ /* Special (socket, fifo, device...) */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, old_encode_dev(rdev));
++#else
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, rdev);
++#endif
++ break;
++ case S_IFREG: /* file */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
++ gid);
++ break;
++ case S_IFDIR: /* directory */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
++ uid, gid);
++ break;
++ case S_IFLNK: /* symlink */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
++ obj = NULL; /* Do we ever get here? */
++ break;
++ }
++
++ /* Can not call yaffs_get_inode() with gross lock held */
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod created object %d count = %d",
++ obj->obj_id, atomic_read(&inode->i_count));
++ error = 0;
++ yaffs_fill_inode_from_obj(dir, parent);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
++ error = -ENOMEM;
++ }
++
++ return error;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++#else
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++ int ret_val;
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++ return ret_val;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ bool dummy)
++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ struct nameidata *n)
++#elif (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
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ unsigned int dummy)
++#elif (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
++{
++ struct yaffs_obj *obj;
++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
++
++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
++
++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
++
++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
++
++ /* Can't hold gross lock when calling yaffs_get_inode() */
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_lookup found %d", obj->obj_id);
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
++
++ }
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *link = NULL;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
++ link =
++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ obj);
++
++ if (link) {
++ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
++ d_instantiate(dentry, old_dentry->d_inode);
++ atomic_inc(&old_dentry->d_inode->i_count);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_link link count %d i_count %d",
++ old_dentry->d_inode->i_nlink,
++ atomic_read(&old_dentry->d_inode->i_count));
++ }
++
++ yaffs_gross_unlock(dev);
++
++ if (link) {
++ update_dir_time(dir);
++ return 0;
++ }
++
++ return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
++
++ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ return -ENAMETOOLONG;
++
++ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
++ YAFFS_MAX_ALIAS_LENGTH)
++ return -ENAMETOOLONG;
++
++ dev = yaffs_inode_to_obj(dir)->my_dev;
++ yaffs_gross_lock(dev);
++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ S_IFLNK | S_IRWXUGO, uid, gid, symname);
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ struct inode *inode;
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
++ return 0;
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
++ }
++
++ return -ENOMEM;
++}
++
++/*
++ * 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)
++{
++ struct yaffs_dev *dev;
++ int ret_val = YAFFS_FAIL;
++ struct yaffs_obj *target;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
++ dev = yaffs_inode_to_obj(old_dir)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ /* Check if the target is an existing directory that is not empty. */
++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++
++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !list_empty(&target->variant.dir_variant.children)) {
++
++ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
++
++ ret_val = YAFFS_FAIL;
++ } else {
++ /* Now does unlinking internally using shadowing mechanism */
++ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
++
++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
++ old_dentry->d_name.name,
++ yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++ }
++ yaffs_gross_unlock(dev);
++
++ if (ret_val == YAFFS_OK) {
++ if (target)
++ inode_dec_link_count(new_dentry->d_inode);
++
++ update_dir_time(old_dir);
++ if (old_dir != new_dir)
++ update_dir_time(new_dir);
++ return 0;
++ } else {
++ return -ENOTEMPTY;
++ }
++}
++
++
++
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int ret_val;
++
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
++ (int)(dir->i_ino), dentry->d_name.name);
++ obj = yaffs_inode_to_obj(dir);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ ret_val = yaffs_unlinker(obj, dentry->d_name.name);
++
++ if (ret_val == YAFFS_OK) {
++ inode_dec_link_count(dentry->d_inode);
++ dir->i_version++;
++ yaffs_gross_unlock(dev);
++ update_dir_time(dir);
++ return 0;
++ }
++ yaffs_gross_unlock(dev);
++ return -ENOTEMPTY;
++}
++
++
++
++static const 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,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the remove_obj_fn to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each struct yaffs_dev has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_search_context {
++ struct yaffs_dev *dev;
++ struct yaffs_obj *dir_obj;
++ struct yaffs_obj *next_return;
++ struct list_head others;
++};
++
++/*
++ * yaffs_new_search() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
++{
++ struct yaffs_dev *dev = dir->my_dev;
++ struct yaffs_search_context *sc =
++ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
++ if (sc) {
++ sc->dir_obj = dir;
++ sc->dev = dev;
++ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else
++ sc->next_return =
++ list_entry(dir->variant.dir_variant.children.next,
++ struct yaffs_obj, siblings);
++ INIT_LIST_HEAD(&sc->others);
++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
++ }
++ return sc;
++}
++
++/*
++ * yaffs_search_end() disposes of a search context and cleans up.
++ */
++static void yaffs_search_end(struct yaffs_search_context *sc)
++{
++ if (sc) {
++ list_del(&sc->others);
++ kfree(sc);
++ }
++}
++
++/*
++ * yaffs_search_advance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_search_advance(struct yaffs_search_context *sc)
++{
++ if (!sc)
++ return;
++
++ if (sc->next_return == NULL ||
++ list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else {
++ struct list_head *next = sc->next_return->siblings.next;
++
++ if (next == &sc->dir_obj->variant.dir_variant.children)
++ sc->next_return = NULL; /* end of list */
++ else
++ sc->next_return =
++ list_entry(next, struct yaffs_obj, siblings);
++ }
++}
++
++/*
++ * yaffs_remove_obj_callback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
++{
++
++ struct list_head *i;
++ struct yaffs_search_context *sc;
++ struct list_head *search_contexts =
++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
++
++ /* Iterate through the directory search contexts.
++ * If any are currently on the object being removed, then advance
++ * the search context to the next object to prevent a hanging pointer.
++ */
++ list_for_each(i, search_contexts) {
++ sc = list_entry(i, struct yaffs_search_context, others);
++ if (sc->next_return == obj)
++ yaffs_search_advance(sc);
++ }
++
++}
++
++
++/*-----------------------------------------------------------------*/
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++static int yaffs_readdir(struct file *file, struct dir_context *ctx)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = file->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(file->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = ctx->pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)file->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dotdot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++
++ curoffs = 1;
++
++ /* If the directory has changed since the open or last call to
++ readdir, rewind to after the 2 canned entries. */
++ if (file->f_version != inode->i_version) {
++ offset = 2;
++ ctx->pos = offset;
++ file->f_version = inode->i_version;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (!dir_emit(ctx, name, strlen(name),
++ this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ ctx->pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#else
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = f->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = f->f_pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ f->f_pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)f->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, "..", 2, offset,
++ f->f_dentry->d_parent->d_inode->i_ino,
++ DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ 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;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (filldir(dirent,
++ name,
++ strlen(name),
++ offset, this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ f->f_pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#endif
++
++static const struct file_operations yaffs_dir_operations = {
++ .read = generic_read_dir,
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++ .iterate = yaffs_readdir,
++#else
++ .readdir = yaffs_readdir,
++#endif
++ .fsync = yaffs_sync_object,
++ .llseek = generic_file_llseek,
++};
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj)
++{
++ if (inode && obj) {
++
++ /* Check mode against the variant type and attempt to repair if broken. */
++ u32 mode = obj->yst_mode;
++ switch (obj->variant_type) {
++ 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_flags |= S_NOATIME;
++
++ inode->i_ino = obj->obj_id;
++ inode->i_mode = obj->yst_mode;
++ i_uid_write(inode, obj->yst_uid);
++ i_gid_write(inode, 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_get_obj_length(obj);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++
++ set_nlink(inode, yaffs_get_obj_link_count(obj));
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
++ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
++ 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_inode_to_obj_lv(inode) = obj;
++
++ obj->my_inode = inode;
++
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode invalid parameters");
++ }
++
++}
++
++
++
++/*
++ * yaffs background thread functions .
++ * yaffs_bg_thread_fn() the thread function
++ * yaffs_bg_start() launches the background thread.
++ * yaffs_bg_stop() cleans up the background thread.
++ *
++ * NB:
++ * The thread should only run after the yaffs is initialised
++ * The thread should be stopped before yaffs is unmounted.
++ * The thread should not do any writing while the fs is in read only.
++ */
++
++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
++{
++ unsigned erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned scattered = 0; /* Free chunks not in an erased block */
++
++ if (erased_chunks < dev->n_free_chunks)
++ scattered = (dev->n_free_chunks - erased_chunks);
++
++ if (!context->bg_running)
++ return 0;
++ else if (scattered < (dev->param.chunks_per_block * 2))
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 2)
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 4)
++ return 1;
++ else
++ return 2;
++}
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++
++void yaffs_background_waker(unsigned long data)
++{
++ wake_up_process((struct task_struct *)data);
++}
++
++static int yaffs_bg_thread_fn(void *data)
++{
++ struct yaffs_dev *dev = (struct yaffs_dev *)data;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned long now = jiffies;
++ unsigned long next_dir_update = now;
++ unsigned long next_gc = now;
++ unsigned long expires;
++ unsigned int urgency;
++
++ int gc_result;
++ struct timer_list timer;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "yaffs_background starting for dev %p", (void *)dev);
++
++#ifdef YAFFS_COMPILE_FREEZER
++ set_freezable();
++#endif
++ while (context->bg_running) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
++
++ if (kthread_should_stop())
++ break;
++
++#ifdef YAFFS_COMPILE_FREEZER
++ if (try_to_freeze())
++ continue;
++#endif
++ yaffs_gross_lock(dev);
++
++ now = jiffies;
++
++ if (time_after(now, next_dir_update) && yaffs_bg_enable) {
++ yaffs_update_dirty_dirs(dev);
++ next_dir_update = now + HZ;
++ }
++
++ if (time_after(now, next_gc) && yaffs_bg_enable) {
++ if (!dev->is_checkpointed) {
++ urgency = yaffs_bg_gc_urgency(dev);
++ gc_result = yaffs_bg_gc(dev, urgency);
++ if (urgency > 1)
++ next_gc = now + HZ / 20 + 1;
++ else if (urgency > 0)
++ next_gc = now + HZ / 10 + 1;
++ else
++ next_gc = now + HZ * 2;
++ } else {
++ /*
++ * gc not running so set to next_dir_update
++ * to cut down on wake ups
++ */
++ next_gc = next_dir_update;
++ }
++ }
++ yaffs_gross_unlock(dev);
++#if 1
++ expires = next_dir_update;
++ if (time_before(next_gc, expires))
++ expires = next_gc;
++ if (time_before(expires, now))
++ expires = now + HZ;
++
++ Y_INIT_TIMER(&timer);
++ timer.expires = expires + 1;
++ timer.data = (unsigned long)current;
++ timer.function = yaffs_background_waker;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_timer(&timer);
++ schedule();
++ del_timer_sync(&timer);
++#else
++ msleep(10);
++#endif
++ }
++
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ int retval = 0;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++
++ if (dev->read_only)
++ return -1;
++
++ context->bg_running = 1;
++
++ context->bg_thread = kthread_run(yaffs_bg_thread_fn,
++ (void *)dev, "yaffs-bg-%d",
++ context->mount_id);
++
++ if (IS_ERR(context->bg_thread)) {
++ retval = PTR_ERR(context->bg_thread);
++ context->bg_thread = NULL;
++ context->bg_running = 0;
++ }
++ return retval;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
++
++ ctxt->bg_running = 0;
++
++ if (ctxt->bg_thread) {
++ kthread_stop(ctxt->bg_thread);
++ ctxt->bg_thread = NULL;
++ }
++}
++#else
++static int yaffs_bg_thread_fn(void *data)
++{
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ return 0;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++}
++#endif
++
++
++static void yaffs_flush_inodes(struct super_block *sb)
++{
++ struct inode *iptr;
++ struct yaffs_obj *obj;
++
++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
++ obj = yaffs_inode_to_obj(iptr);
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "flushing obj %d",
++ obj->obj_id);
++ yaffs_flush_file(obj, 1, 0);
++ }
++ }
++}
++
++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ if (!dev)
++ return;
++
++ yaffs_flush_inodes(sb);
++ yaffs_update_dirty_dirs(dev);
++ yaffs_flush_whole_cache(dev);
++ if (do_checkpoint)
++ yaffs_checkpoint_save(dev);
++}
++
++static LIST_HEAD(yaffs_context_list);
++struct mutex yaffs_context_lock;
++
++static void yaffs_put_super(struct super_block *sb)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super");
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "Shutting down yaffs background thread");
++ yaffs_bg_stop(dev);
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "yaffs background thread shut down");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_super(sb, 1);
++
++ yaffs_deinitialise(dev);
++
++ yaffs_gross_unlock(dev);
++
++ mutex_lock(&yaffs_context_lock);
++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
++ mutex_unlock(&yaffs_context_lock);
++
++ if (yaffs_dev_to_lc(dev)->spare_buffer) {
++ kfree(yaffs_dev_to_lc(dev)->spare_buffer);
++ yaffs_dev_to_lc(dev)->spare_buffer = NULL;
++ }
++
++ kfree(dev);
++
++ yaffs_put_mtd_device(mtd);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super done");
++}
++
++
++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
++{
++ return yaffs_gc_control;
++}
++
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++
++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
++ uint32_t generation)
++{
++ return Y_IGET(sb, ino);
++}
++
++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++struct dentry *yaffs2_get_parent(struct dentry *dentry)
++{
++
++ struct super_block *sb = dentry->d_inode->i_sb;
++ struct dentry *parent = ERR_PTR(-ENOENT);
++ struct inode *inode;
++ unsigned long parent_ino;
++ struct yaffs_obj *d_obj;
++ struct yaffs_obj *parent_obj;
++
++ d_obj = yaffs_inode_to_obj(dentry->d_inode);
++
++ if (d_obj) {
++ parent_obj = d_obj->parent;
++ if (parent_obj) {
++ parent_ino = yaffs_get_obj_inode(parent_obj);
++ inode = Y_IGET(sb, parent_ino);
++
++ if (IS_ERR(inode)) {
++ parent = ERR_CAST(inode);
++ } else {
++ parent = d_obtain_alias(inode);
++ if (!IS_ERR(parent)) {
++ parent = ERR_PTR(-ENOMEM);
++ iput(inode);
++ }
++ }
++ }
++ }
++
++ return parent;
++}
++
++/* Just declare a zero structure as a NULL value implies
++ * using the default functions of exportfs.
++ */
++
++static struct export_operations yaffs_export_ops = {
++ .fh_to_dentry = yaffs2_fh_to_dentry,
++ .fh_to_parent = yaffs2_fh_to_parent,
++ .get_parent = yaffs2_get_parent,
++};
++
++#endif
++
++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
++{
++ /* Clear the association between the inode and
++ * the struct yaffs_obj.
++ */
++ obj->my_inode = NULL;
++ yaffs_inode_to_obj_lv(inode) = NULL;
++
++ /* If the object freeing was deferred, then the real
++ * free happens now.
++ * This should fix the inode inconsistency problem.
++ */
++ yaffs_handle_defered_free(obj);
++}
++
++#ifdef YAFFS_HAS_EVICT_INODE
++/* yaffs_evict_inode combines into one operation what was previously done in
++ * yaffs_clear_inode() and yaffs_delete_inode()
++ *
++ */
++static void yaffs_evict_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ int deleteme = 0;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_evict_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (!inode->i_nlink && !is_bad_inode(inode))
++ deleteme = 1;
++ truncate_inode_pages(&inode->i_data, 0);
++ Y_CLEAR_INODE(inode);
++
++ if (deleteme && obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(dev);
++ }
++}
++#else
++
++/* clear is called to tell the fs to release any per-inode data it holds.
++ * The object might still exist on disk and is just being thrown out of the cache
++ * or else the object has actually been deleted and we're being called via
++ * the chain
++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
++ */
++
++static void yaffs_clear_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_clear_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(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)
++{
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_delete_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ truncate_inode_pages(&inode->i_data, 0);
++#endif
++ clear_inode(inode);
++}
++#endif
++
++
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++ 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)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#endif
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
++
++ yaffs_gross_lock(dev);
++
++ buf->f_type = YAFFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_namelen = 255;
++
++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
++ /* Do this if chunk size is not a power of 2 */
++
++ uint64_t bytes_in_dev;
++ uint64_t bytes_free;
++
++ bytes_in_dev =
++ ((uint64_t)
++ ((dev->param.end_block - dev->param.start_block +
++ 1))) * ((uint64_t) (dev->param.chunks_per_block *
++ dev->data_bytes_per_chunk));
++
++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
++ buf->f_blocks = bytes_in_dev;
++
++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
++ ((uint64_t) (dev->data_bytes_per_chunk));
++
++ do_div(bytes_free, sb->s_blocksize);
++
++ buf->f_bfree = bytes_free;
++
++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
++
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ } else {
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++ }
++
++ buf->f_files = 0;
++ buf->f_ffree = 0;
++ buf->f_bavail = buf->f_bfree;
++
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++
++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
++{
++
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
++ int do_checkpoint;
++ int dirty = yaffs_check_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
++ gc_urgent,
++ dirty ? "dirty" : "clean",
++ request_checkpoint ? "checkpoint requested" : "no checkpoint",
++ oneshot_checkpoint ? " one-shot" : "");
++
++ yaffs_gross_lock(dev);
++ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
++ oneshot_checkpoint) && !dev->is_checkpointed;
++
++ if (dirty || do_checkpoint) {
++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
++ yaffs_clear_super_dirty(dev);
++ if (oneshot_checkpoint)
++ yaffs_auto_checkpoint &= ~4;
++ }
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#ifdef YAFFS_HAS_WRITE_SUPER
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_write_super %s",
++ request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++ return 0;
++#endif
++}
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++ return 0;
++}
++
++
++
++static const struct super_operations yaffs_super_ops = {
++ .statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++ .read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++ .put_inode = yaffs_put_inode,
++#endif
++ .put_super = yaffs_put_super,
++#ifdef YAFFS_HAS_EVICT_INODE
++ .evict_inode = yaffs_evict_inode,
++#else
++ .delete_inode = yaffs_delete_inode,
++ .clear_inode = yaffs_clear_inode,
++#endif
++ .sync_fs = yaffs_sync_fs,
++#ifdef YAFFS_HAS_WRITE_SUPER
++ .write_super = yaffs_write_super,
++#endif
++};
++
++struct yaffs_options {
++ int inband_tags;
++ int skip_checkpoint_read;
++ int skip_checkpoint_write;
++ int no_cache;
++ int tags_ecc_on;
++ int tags_ecc_overridden;
++ int lazy_loading_enabled;
++ int lazy_loading_overridden;
++ int empty_lost_and_found;
++ int empty_lost_and_found_overridden;
++ int disable_summary;
++};
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(struct 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++;
++
++ 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, "tags-ecc-off")) {
++ options->tags_ecc_on = 0;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "tags-ecc-on")) {
++ options->tags_ecc_on = 1;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-off")) {
++ options->lazy_loading_enabled = 0;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-on")) {
++ options->lazy_loading_enabled = 1;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "disable-summary")) {
++ options->disable_summary = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
++ options->empty_lost_and_found = 0;
++ options->empty_lost_and_found_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
++ options->empty_lost_and_found = 1;
++ options->empty_lost_and_found_overridden = 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 dentry *yaffs_make_root(struct inode *inode)
++{
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++ struct dentry *root = d_alloc_root(inode);
++
++ if (!root)
++ iput(inode);
++
++ return root;
++#else
++ return d_make_root(inode);
++#endif
++}
++
++
++
++
++static struct super_block *yaffs_internal_read_super(int yaffs_version,
++ struct super_block *sb,
++ void *data, int silent)
++{
++ int n_blocks;
++ struct inode *inode = NULL;
++ struct dentry *root;
++ struct yaffs_dev *dev = 0;
++ char devname_buf[BDEVNAME_SIZE + 1];
++ struct mtd_info *mtd;
++ int err;
++ char *data_str = (char *)data;
++ struct yaffs_linux_context *context = NULL;
++ struct yaffs_param *param;
++
++ int read_only = 0;
++ int inband_tags = 0;
++
++ struct yaffs_options options;
++
++ unsigned mount_id;
++ int found;
++ struct yaffs_linux_context *context_iterator;
++ struct list_head *l;
++
++ if (!sb) {
++ printk(KERN_INFO "yaffs: sb is NULL\n");
++ return NULL;
++ }
++
++ sb->s_magic = YAFFS_MAGIC;
++ sb->s_op = &yaffs_super_ops;
++ sb->s_flags |= MS_NOATIME;
++
++ read_only = ((sb->s_flags & MS_RDONLY) != 0);
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++ sb->s_export_op = &yaffs_export_ops;
++#endif
++
++ 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\" %s\n",
++ sb->s_dev,
++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
++
++ 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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: Using yaffs%d", yaffs_version);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
++ MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ yaffs_devname(sb, devname_buf));
++
++ /* Get the device */
++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++ if (IS_ERR(mtd)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device %u either not valid or unavailable",
++ MINOR(sb->s_dev));
++ return NULL;
++ }
++
++ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
++ yaffs_version = 2;
++ }
++
++ /* Added NCB 26/5/2006 for completeness */
++ if (yaffs_version == 2 && !options.inband_tags
++ && WRITE_SIZE(mtd) == 512) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
++ yaffs_version = 1;
++ }
++
++ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
++ options.inband_tags)
++ inband_tags = 1;
++
++ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++ 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 struct yaffs_dev up for mtd
++ */
++
++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++ read_only = 1;
++ printk(KERN_INFO
++ "yaffs: mtd is read only, setting superblock read only\n"
++ );
++ sb->s_flags |= MS_RDONLY;
++ }
++
++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
++
++ if (!dev || !context) {
++ kfree(dev);
++ kfree(context);
++ dev = NULL;
++ context = NULL;
++
++ /* Deep shit could not allocate device structure */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
++ );
++ return NULL;
++ }
++ memset(dev, 0, sizeof(struct yaffs_dev));
++ param = &(dev->param);
++
++ memset(context, 0, sizeof(struct yaffs_linux_context));
++ dev->os_context = context;
++ INIT_LIST_HEAD(&(context->context_list));
++ context->dev = dev;
++ context->super = sb;
++
++ dev->read_only = read_only;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ sb->s_fs_info = dev;
++#else
++ sb->u.generic_sbp = dev;
++#endif
++
++
++ dev->driver_context = mtd;
++ param->name = mtd->name;
++
++ /* Set up the memory size parameters.... */
++
++
++ param->n_reserved_blocks = 5;
++ param->n_caches = (options.no_cache) ? 0 : 10;
++ param->inband_tags = inband_tags;
++
++ param->enable_xattr = 1;
++ if (options.lazy_loading_overridden)
++ param->disable_lazy_load = !options.lazy_loading_enabled;
++
++ param->defered_dir_update = 1;
++
++ if (options.tags_ecc_overridden)
++ param->no_tags_ecc = !options.tags_ecc_on;
++
++ param->empty_lost_n_found = 1;
++ param->refresh_period = 500;
++ param->disable_summary = options.disable_summary;
++
++
++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
++ param->disable_bad_block_marking = 1;
++#endif
++ if (options.empty_lost_and_found_overridden)
++ param->empty_lost_n_found = options.empty_lost_and_found;
++
++ /* ... and the functions. */
++ if (yaffs_version == 2) {
++ param->is_yaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ param->total_bytes_per_chunk = mtd->writesize;
++ param->chunks_per_block = mtd->erasesize / mtd->writesize;
++#else
++ param->total_bytes_per_chunk = mtd->oobblock;
++ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
++#endif
++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++ } else {
++ param->is_yaffs2 = 0;
++ n_blocks = YCALCBLOCKS(mtd->size,
++ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
++
++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
++ }
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++
++ yaffs_mtd_drv_install(dev);
++
++ param->sb_dirty_fn = yaffs_set_super_dirty;
++ param->gc_control_fn = yaffs_gc_control_callback;
++
++ yaffs_dev_to_lc(dev)->super = sb;
++
++ param->use_nand_ecc = 1;
++
++ param->skip_checkpt_rd = options.skip_checkpoint_read;
++ param->skip_checkpt_wr = options.skip_checkpoint_write;
++
++ mutex_lock(&yaffs_context_lock);
++ /* Get a mount id */
++ found = 0;
++ for (mount_id = 0; !found; mount_id++) {
++ found = 1;
++ list_for_each(l, &yaffs_context_list) {
++ context_iterator =
++ list_entry(l, struct yaffs_linux_context,
++ context_list);
++ if (context_iterator->mount_id == mount_id)
++ found = 0;
++ }
++ }
++ context->mount_id = mount_id;
++
++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
++ &yaffs_context_list);
++ mutex_unlock(&yaffs_context_lock);
++
++ /* Directory search handling... */
++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
++ param->remove_obj_fn = yaffs_remove_obj_callback;
++
++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
++
++ yaffs_gross_lock(dev);
++
++ err = yaffs_guts_initialise(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: guts initialised %s",
++ (err == YAFFS_OK) ? "OK" : "FAILED");
++
++ if (err == YAFFS_OK)
++ yaffs_bg_start(dev);
++
++ if (!context->bg_thread)
++ param->defered_dir_update = 0;
++
++ sb->s_maxbytes = yaffs_max_file_size(dev);
++
++ /* Release lock before yaffs_get_inode() */
++ yaffs_gross_unlock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
++
++ root = yaffs_make_root(inode);
++
++ if (!root)
++ return NULL;
++
++ sb->s_root = root;
++ if(!dev->is_checkpointed)
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
++ 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, 39))
++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs_mount,
++#else
++ .get_sb = yaffs_read_super,
++#endif
++ .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
++
++
++#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, 39))
++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs2_mount,
++#else
++ .get_sb = yaffs2_read_super,
++#endif
++ .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
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++static struct proc_dir_entry *my_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
++{
++ struct yaffs_param *param = &dev->param;
++ int bs[10];
++
++ yaffs_count_blocks_by_state(dev,bs);
++
++ buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
++ buf += sprintf(buf, "end_block............ %d\n", param->end_block);
++ buf += sprintf(buf, "total_bytes_per_chunk %d\n",
++ param->total_bytes_per_chunk);
++ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
++ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
++ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
++ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
++ buf += sprintf(buf, "empty_lost_n_found... %d\n",
++ param->empty_lost_n_found);
++ buf += sprintf(buf, "disable_lazy_load.... %d\n",
++ param->disable_lazy_load);
++ buf += sprintf(buf, "disable_bad_block_mrk %d\n",
++ param->disable_bad_block_marking);
++ buf += sprintf(buf, "refresh_period....... %d\n",
++ param->refresh_period);
++ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
++ buf += sprintf(buf, "n_reserved_blocks.... %d\n",
++ param->n_reserved_blocks);
++ buf += sprintf(buf, "always_check_erased.. %d\n",
++ param->always_check_erased);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "block count by state\n");
++ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
++ bs[0], bs[1], bs[2], bs[3], bs[4]);
++ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
++ bs[5], bs[6], bs[7], bs[8], bs[9]);
++
++ return buf;
++}
++
++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
++{
++ buf += sprintf(buf, "max file size....... %lld\n",
++ (long long) yaffs_max_file_size(dev));
++ buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
++ dev->data_bytes_per_chunk);
++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
++ buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
++ dev->blocks_in_checkpt);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
++ buf += sprintf(buf, "passive_gc_count..... %u\n",
++ dev->passive_gc_count);
++ buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
++ dev->oldest_dirty_gc_count);
++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
++ buf += sprintf(buf, "n_retried_writes..... %u\n",
++ dev->n_retried_writes);
++ buf += sprintf(buf, "n_retired_blocks..... %u\n",
++ dev->n_retired_blocks);
++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
++ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
++ dev->n_tags_ecc_fixed);
++ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
++ dev->n_tags_ecc_unfixed);
++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
++ buf += sprintf(buf, "n_unlinked_files..... %u\n",
++ dev->n_unlinked_files);
++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
++ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
++ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
++
++ 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 dev_list.
++ * 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,
++ "Multi-version YAFFS built:" __DATE__ " " __TIME__
++ "\n");
++ else if (step == 1)
++ buf += sprintf(buf, "\n");
++ else {
++ step -= 2;
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (n < (step & ~1)) {
++ n += 2;
++ continue;
++ }
++ if ((step & 1) == 0) {
++ buf +=
++ sprintf(buf, "\nDevice %d \"%s\"\n", n,
++ dev->param.name);
++ buf = yaffs_dump_dev_part0(buf, dev);
++ } else {
++ buf = yaffs_dump_dev_part1(buf, dev);
++ }
++
++ break;
++ }
++ mutex_unlock(&yaffs_context_lock);
++ }
++
++ 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},
++ {"background", YAFFS_TRACE_BACKGROUND},
++ {"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},
++ {"lock", YAFFS_TRACE_LOCK},
++ {"mtd", YAFFS_TRACE_MTD},
++ {"nandaccess", YAFFS_TRACE_NANDACCESS},
++ {"os", YAFFS_TRACE_OS},
++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++ {"scan", YAFFS_TRACE_SCAN},
++ {"mount", YAFFS_TRACE_MOUNT},
++ {"tracing", YAFFS_TRACE_TRACING},
++ {"sync", YAFFS_TRACE_SYNC},
++ {"write", YAFFS_TRACE_WRITE},
++ {"verify", YAFFS_TRACE_VERIFY},
++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
++ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
++ {"all", 0xffffffff},
++ {"none", 0},
++ {NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(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_trace_mask;
++
++ 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_trace_mask = rg | YAFFS_TRACE_ALWAYS;
++
++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
++
++ 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(KERN_DEBUG "%c%s\n", flag,
++ mask_flags[i].mask_name);
++ }
++ }
++
++ return count;
++}
++
++/* Debug strings are of the form:
++ * .bnnn print info on block n
++ * .cobjn,chunkn print nand chunk id for objn:chunkn
++ */
++
++static int yaffs_proc_debug_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++
++ char str[100];
++ char *p0;
++ char *p1;
++ long p1_val;
++ long p0_val;
++ char cmd;
++ struct list_head *item;
++
++ memset(str, 0, sizeof(str));
++ memcpy(str, buf, min(count, sizeof(str) -1));
++
++ cmd = str[1];
++
++ p0 = str + 2;
++
++ p1 = p0;
++
++ while (*p1 && *p1 != ',') {
++ p1++;
++ }
++ *p1 = '\0';
++ p1++;
++
++ p0_val = simple_strtol(p0, NULL, 0);
++ p1_val = simple_strtol(p1, NULL, 0);
++
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (cmd == 'b') {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev,p0_val);
++
++ if(bi) {
++ printk("Block %d: state %d, retire %d, use %d, seq %d\n",
++ (int)p0_val, bi->block_state,
++ bi->needs_retiring, bi->pages_in_use,
++ bi->seq_number);
++ }
++ } else if (cmd == 'c') {
++ struct yaffs_obj *obj;
++ int nand_chunk;
++
++ obj = yaffs_find_by_number(dev, p0_val);
++ if (!obj)
++ printk("No obj %d\n", (int)p0_val);
++ else {
++ if(p1_val == 0)
++ nand_chunk = obj->hdr_chunk;
++ else
++ nand_chunk =
++ yaffs_find_chunk_in_file(obj,
++ p1_val, NULL);
++ printk("Nand chunk for %d:%d is %d\n",
++ (int)p0_val, (int)p1_val, nand_chunk);
++ }
++ }
++ }
++
++ mutex_unlock(&yaffs_context_lock);
++
++ return count;
++}
++
++static int yaffs_proc_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ if (buf[0] == '.')
++ return yaffs_proc_debug_write(file, buf, count, data);
++ return yaffs_proc_write_trace_options(file, buf, count, data);
++}
++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
++
++/* 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[] = {
++ {&yaffs_fs_type, 0},
++ {&yaffs2_fs_type, 0},
++ {NULL, 0}
++};
++
++static int __init init_yaffs_fs(void)
++{
++ int error = 0;
++ struct file_system_to_install *fsinst;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " Installing.");
++
++ mutex_init(&yaffs_context_lock);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ /* Install the proc_fs entries */
++ my_proc_entry = create_proc_entry("yaffs",
++ S_IRUGO | S_IFREG, YPROC_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;
++ }
++#endif
++
++ /* 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;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " removing.");
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ remove_proc_entry("yaffs", YPROC_ROOT);
++#endif
++
++ 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-2011");
++MODULE_LICENSE("GPL");
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.12.20/fs/yaffs2/yaffs_yaffs1.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_yaffs1.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,422 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_yaffs1.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++#include "yaffs_attribs.h"
++
++int yaffs1_scan(struct yaffs_dev *dev)
++{
++ struct yaffs_ext_tags tags;
++ int blk;
++ int result;
++ int chunk;
++ int c;
++ int deleted;
++ enum yaffs_block_state state;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int alloc_failed = 0;
++ struct yaffs_shadow_fixer *shadow_fixers = NULL;
++ u8 *chunk_data;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs1_scan starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, state, seq_number);
++
++ if (state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ }
++ bi++;
++ }
++
++ /* For each block.... */
++ for (blk = dev->internal_start_block;
++ !alloc_failed && blk <= dev->internal_end_block; blk++) {
++
++ cond_resched();
++
++ bi = yaffs_get_block_info(dev, blk);
++ state = bi->block_state;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ for (c = 0;
++ !alloc_failed && c < dev->param.chunks_per_block &&
++ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
++ /* Read the tags and decide what to do */
++ chunk = blk * dev->param.chunks_per_block + c;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
++ tags.is_deleted) {
++ /* YAFFS1 only...
++ * A deleted chunk
++ */
++ deleted++;
++ dev->n_free_chunks++;
++ } else if (!tags.chunk_used) {
++ /* An unassigned chunk in the block
++ * This means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (c == 0) {
++ /* We're looking at the first chunk in
++ *the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ /* this is the block being allocated */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, c);
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = c;
++ dev->alloc_block_finder = blk;
++
++ }
++
++ dev->n_free_chunks +=
++ (dev->param.chunks_per_block - c);
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ unsigned int endpos;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ /* PutChunkIntoFile checks for a clash
++ * (two data chunks with the same chunk_id).
++ */
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in) {
++ if (!yaffs_put_chunk_in_file
++ (in, tags.chunk_id, chunk, 1))
++ alloc_failed = 1;
++ }
++
++ endpos =
++ (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk +
++ tags.n_bytes;
++ if (in &&
++ in->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE &&
++ in->variant.file_variant.scanned_size <
++ endpos) {
++ in->variant.file_variant.scanned_size =
++ endpos;
++ if (!dev->param.use_header_file_size) {
++ in->variant.
++ file_variant.file_size =
++ in->variant.
++ file_variant.scanned_size;
++ }
++
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Make the object
++ */
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ in = yaffs_find_by_number(dev, tags.obj_id);
++ if (in && in->variant_type != oh->type) {
++ /* This should not happen, but somehow
++ * Wev'e ended up with an obj_id that
++ * has been reused but not yet deleted,
++ * and worse still it has changed type.
++ * Delete the old object.
++ */
++
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ oh->type);
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in && oh->shadows_obj > 0) {
++
++ struct yaffs_shadow_fixer *fixer;
++ fixer =
++ kmalloc(sizeof
++ (struct yaffs_shadow_fixer),
++ GFP_NOFS);
++ if (fixer) {
++ fixer->next = shadow_fixers;
++ shadow_fixers = fixer;
++ fixer->obj_id = tags.obj_id;
++ fixer->shadowed_id =
++ oh->shadows_obj;
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Shadow fixer: %d shadows %d",
++ fixer->obj_id,
++ fixer->shadowed_id);
++
++ }
++
++ }
++
++ if (in && in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate and need to
++ * resolve it. */
++
++ unsigned existing_serial = in->serial;
++ unsigned new_serial =
++ tags.serial_number;
++
++ if (((existing_serial + 1) & 3) ==
++ new_serial) {
++ /* Use new one - destroy the
++ * exisiting one */
++ yaffs_chunk_del(dev,
++ in->hdr_chunk,
++ 1, __LINE__);
++ in->valid = 0;
++ } else {
++ /* Use existing - destroy
++ * this one. */
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++ }
++ }
++
++ if (in && !in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ } else if (in && !in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ in->dirty = 0;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (!parent)
++ alloc_failed = 1;
++ if (parent && parent->variant_type ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.
++ children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, a problem....
++ * We're trying to use a
++ * non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (dev->param.
++ use_header_file_size)
++ in->variant.
++ file_variant.file_size
++ = yaffs_oh_to_size(oh);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.
++ hardlink_variant.equiv_id =
++ oh->equiv_id;
++ list_add(&in->hard_links,
++ &hard_list);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.
++ alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.
++ symlink_variant.alias)
++ alloc_failed = 1;
++ break;
++ }
++ }
++ }
++ }
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning,
++ * then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ /* If the block was partially allocated then
++ * treat it as fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ bi->block_state = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ yaffs_block_became_dirty(dev, blk);
++ }
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add
++ * these hardlinks.
++ */
++
++ yaffs_link_fixup(dev, &hard_list);
++
++ /*
++ * Fix up any shadowed objects.
++ * There should not be more than one of these.
++ */
++ {
++ struct yaffs_shadow_fixer *fixer;
++ struct yaffs_obj *obj;
++
++ while (shadow_fixers) {
++ fixer = shadow_fixers;
++ shadow_fixers = fixer->next;
++ /* Complete the rename transaction by deleting the
++ * shadowed object then setting the object header
++ to unshadowed.
++ */
++ obj = yaffs_find_by_number(dev, fixer->shadowed_id);
++ if (obj)
++ yaffs_del_obj(obj);
++
++ obj = yaffs_find_by_number(dev, fixer->obj_id);
++
++ if (obj)
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ kfree(fixer);
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.12.20/fs/yaffs2/yaffs_yaffs1.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_yaffs1.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS1_H__
++#define __YAFFS_YAFFS1_H__
++
++#include "yaffs_guts.h"
++int yaffs1_scan(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.12.20/fs/yaffs2/yaffs_yaffs2.c
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_yaffs2.c 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,1534 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_checkptrw.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_verify.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/*
++ * Checkpoints are really no benefit on very small partitions.
++ *
++ * To save space on small partitions don't bother with checkpoints unless
++ * the partition is at least this big.
++ */
++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
++#define YAFFS_SMALL_HOLE_THRESHOLD 4
++
++/*
++ * Oldest Dirty Sequence Number handling.
++ */
++
++/* yaffs_calc_oldest_dirty_seq()
++ * yaffs2_find_oldest_dirty_seq()
++ * Calculate the oldest dirty sequence number if we don't know it.
++ */
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ int i;
++ unsigned seq;
++ unsigned block_no = 0;
++ struct yaffs_block_info *b;
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ /* Find the oldest dirty sequence number. */
++ seq = dev->seq_number + 1;
++ b = dev->block_info;
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
++ (b->pages_in_use - b->soft_del_pages) <
++ dev->param.chunks_per_block &&
++ b->seq_number < seq) {
++ seq = b->seq_number;
++ block_no = i;
++ }
++ b++;
++ }
++
++ if (block_no) {
++ dev->oldest_dirty_seq = seq;
++ dev->oldest_dirty_block = block_no;
++ }
++}
++
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->oldest_dirty_seq)
++ yaffs_calc_oldest_dirty_seq(dev);
++}
++
++/*
++ * yaffs_clear_oldest_dirty_seq()
++ * Called when a block is erased or marked bad. (ie. when its seq_number
++ * becomes invalid). If the value matches the oldest then we clear
++ * dev->oldest_dirty_seq to force its recomputation.
++ */
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++ }
++}
++
++/*
++ * yaffs2_update_oldest_dirty_seq()
++ * Update the oldest dirty sequence number whenever we dirty a block.
++ * Only do this if the oldest_dirty_seq is actually being tracked.
++ */
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (dev->oldest_dirty_seq) {
++ if (dev->oldest_dirty_seq > bi->seq_number) {
++ dev->oldest_dirty_seq = bi->seq_number;
++ dev->oldest_dirty_block = block_no;
++ }
++ }
++}
++
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return 1; /* disqualification only applies to yaffs2. */
++
++ if (!bi->has_shrink_hdr)
++ return 1; /* can gc */
++
++ yaffs2_find_oldest_dirty_seq(dev);
++
++ /* Can't do gc of this block if there are any blocks older than this
++ * one that have discarded pages.
++ */
++ return (bi->seq_number <= dev->oldest_dirty_seq);
++}
++
++/*
++ * yaffs2_find_refresh_block()
++ * periodically finds the oldest full block by sequence number for refreshing.
++ * Only for yaffs2.
++ */
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
++{
++ u32 b;
++ u32 oldest = 0;
++ u32 oldest_seq = 0;
++ struct yaffs_block_info *bi;
++
++ if (!dev->param.is_yaffs2)
++ return oldest;
++
++ /*
++ * If refresh period < 10 then refreshing is disabled.
++ */
++ if (dev->param.refresh_period < 10)
++ return oldest;
++
++ /*
++ * Fix broken values.
++ */
++ if (dev->refresh_skip > dev->param.refresh_period)
++ dev->refresh_skip = dev->param.refresh_period;
++
++ if (dev->refresh_skip > 0)
++ return oldest;
++
++ /*
++ * Refresh skip is now zero.
++ * We'll do a refresh this time around....
++ * Update the refresh skip and find the oldest block.
++ */
++ dev->refresh_skip = dev->param.refresh_period;
++ dev->refresh_count++;
++ bi = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++
++ if (oldest < 1 || bi->seq_number < oldest_seq) {
++ oldest = b;
++ oldest_seq = bi->seq_number;
++ }
++ }
++ bi++;
++ }
++
++ if (oldest > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC refresh count %d selected block %d with seq_number %d",
++ dev->refresh_count, oldest, oldest_seq);
++ }
++
++ return oldest;
++}
++
++int yaffs2_checkpt_required(struct yaffs_dev *dev)
++{
++ int nblocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ return !dev->param.skip_checkpt_wr &&
++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
++}
++
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
++{
++ int retval;
++ int n_bytes = 0;
++ int n_blocks;
++ int dev_blocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
++ /* Not a valid value so recalculate */
++ dev_blocks = dev->param.end_block - dev->param.start_block + 1;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(struct yaffs_checkpt_dev);
++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
++ n_bytes += dev_blocks * dev->chunk_bit_stride;
++ n_bytes +=
++ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
++ dev->n_obj;
++ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(u32); /* checksum */
++
++ /* Round up and add 2 blocks to allow for some bad blocks,
++ * so add 3 */
++
++ n_blocks =
++ (n_bytes /
++ (dev->data_bytes_per_chunk *
++ dev->param.chunks_per_block)) + 3;
++
++ dev->checkpoint_blocks_required = n_blocks;
++ }
++
++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
++ if (retval < 0)
++ retval = 0;
++ return retval;
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++
++ memset(&cp, 0, sizeof(cp));
++
++ cp.struct_type = sizeof(cp);
++ cp.magic = YAFFS_MAGIC;
++ cp.version = YAFFS_CHECKPOINT_VERSION;
++ cp.head = (head) ? 1 : 0;
++
++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok)
++ ok = (cp.struct_type == sizeof(cp)) &&
++ (cp.magic == YAFFS_MAGIC) &&
++ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++ (cp.head == ((head) ? 1 : 0));
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
++ struct yaffs_dev *dev)
++{
++ cp->n_erased_blocks = dev->n_erased_blocks;
++ cp->alloc_block = dev->alloc_block;
++ cp->alloc_page = dev->alloc_page;
++ cp->n_free_chunks = dev->n_free_chunks;
++
++ cp->n_deleted_files = dev->n_deleted_files;
++ cp->n_unlinked_files = dev->n_unlinked_files;
++ cp->n_bg_deletions = dev->n_bg_deletions;
++ cp->seq_number = dev->seq_number;
++
++}
++
++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
++ struct yaffs_checkpt_dev *cp)
++{
++ dev->n_erased_blocks = cp->n_erased_blocks;
++ dev->alloc_block = cp->alloc_block;
++ dev->alloc_page = cp->alloc_page;
++ dev->n_free_chunks = cp->n_free_chunks;
++
++ dev->n_deleted_files = cp->n_deleted_files;
++ dev->n_unlinked_files = cp->n_unlinked_files;
++ dev->n_bg_deletions = cp->n_bg_deletions;
++ dev->seq_number = cp->seq_number;
++}
++
++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ int ok;
++
++ /* Write device runtime values */
++ yaffs2_dev_to_checkpt_dev(&cp, dev);
++ cp.struct_type = sizeof(cp);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ /* Write block info */
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
++ if (!ok)
++ return 0;
++
++ /* Write chunk bits */
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks =
++ (dev->internal_end_block - dev->internal_start_block + 1);
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ if (cp.struct_type != sizeof(cp))
++ return 0;
++
++ yaffs_checkpt_dev_to_dev(dev, &cp);
++
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++
++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
++
++ if (!ok)
++ return 0;
++
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++
++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
++ struct yaffs_obj *obj)
++{
++ cp->obj_id = obj->obj_id;
++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
++ cp->hdr_chunk = obj->hdr_chunk;
++ cp->variant_type = obj->variant_type;
++ cp->deleted = obj->deleted;
++ cp->soft_del = obj->soft_del;
++ cp->unlinked = obj->unlinked;
++ cp->fake = obj->fake;
++ cp->rename_allowed = obj->rename_allowed;
++ cp->unlink_allowed = obj->unlink_allowed;
++ cp->serial = obj->serial;
++ cp->n_data_chunks = obj->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
++}
++
++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
++ struct yaffs_checkpt_obj *cp)
++{
++ struct yaffs_obj *parent;
++
++ if (obj->variant_type != cp->variant_type) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
++ cp->obj_id, cp->variant_type, cp->hdr_chunk,
++ obj->variant_type);
++ return 0;
++ }
++
++ obj->obj_id = cp->obj_id;
++
++ if (cp->parent_id)
++ parent = yaffs_find_or_create_by_number(obj->my_dev,
++ cp->parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ else
++ parent = NULL;
++
++ if (parent) {
++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
++ cp->obj_id, cp->parent_id,
++ cp->variant_type, cp->hdr_chunk,
++ parent->variant_type);
++ return 0;
++ }
++ yaffs_add_obj_to_dir(parent, obj);
++ }
++
++ obj->hdr_chunk = cp->hdr_chunk;
++ obj->variant_type = cp->variant_type;
++ obj->deleted = cp->deleted;
++ obj->soft_del = cp->soft_del;
++ obj->unlinked = cp->unlinked;
++ obj->fake = cp->fake;
++ obj->rename_allowed = cp->rename_allowed;
++ obj->unlink_allowed = cp->unlink_allowed;
++ obj->serial = cp->serial;
++ obj->n_data_chunks = cp->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
++
++ if (obj->hdr_chunk > 0)
++ obj->lazy_loaded = 1;
++ return 1;
++}
++
++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
++ struct yaffs_tnode *tn, u32 level,
++ int chunk_offset)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++ int ok = 1;
++ u32 base_offset;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (!tn->internal[i])
++ continue;
++ ok = yaffs2_checkpt_tnode_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS) + i);
++ }
++ return ok;
++ }
++
++ /* Level 0 tnode */
++ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
++ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
++ sizeof(base_offset));
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++
++ return ok;
++}
++
++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 end_marker = ~0;
++ int ok = 1;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return ok;
++
++ ok = yaffs2_checkpt_tnode_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.file_variant.
++ top_level, 0);
++ if (ok)
++ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
++ sizeof(end_marker)) == sizeof(end_marker));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 base_chunk;
++ int ok = 1;
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
++ struct yaffs_tnode *tn;
++ int nread = 0;
++
++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
++ sizeof(base_chunk));
++
++ while (ok && (~base_chunk)) {
++ nread++;
++ /* Read level 0 tnode */
++
++ tn = yaffs_get_tnode(dev);
++ if (tn)
++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++ else
++ ok = 0;
++
++ if (tn && ok)
++ ok = yaffs_add_find_tnode_0(dev,
++ file_stuct_ptr,
++ base_chunk, tn) ? 1 : 0;
++
++ if (ok)
++ ok = (yaffs2_checkpt_rd
++ (dev, &base_chunk,
++ sizeof(base_chunk)) == sizeof(base_chunk));
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read tnodes %d records, last %d. ok %d",
++ nread, base_chunk, ok);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int i;
++ int ok = 1;
++ struct list_head *lh;
++
++ /* Iterate through the objects in each hash entry,
++ * dumping them to the checkpointing stream.
++ */
++
++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ if (!obj->defered_free) {
++ yaffs2_obj_checkpt_obj(&cp, obj);
++ cp.struct_type = sizeof(cp);
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
++ cp.obj_id, cp.parent_id,
++ cp.variant_type, cp.hdr_chunk, obj);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp,
++ sizeof(cp)) == sizeof(cp));
++
++ if (ok &&
++ obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE)
++ ok = yaffs2_wr_checkpt_tnodes(obj);
++ }
++ }
++ }
++
++ /* Dump end of list */
++ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
++ cp.struct_type = sizeof(cp);
++
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int ok = 1;
++ int done = 0;
++ LIST_HEAD(hard_list);
++
++
++ while (ok && !done) {
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (cp.struct_type != sizeof(cp)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "struct size %d instead of %d ok %d",
++ cp.struct_type, (int)sizeof(cp), ok);
++ ok = 0;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read object %d parent %d type %d chunk %d ",
++ cp.obj_id, cp.parent_id, cp.variant_type,
++ cp.hdr_chunk);
++
++ if (ok && cp.obj_id == ~0) {
++ done = 1;
++ } else if (ok) {
++ obj =
++ yaffs_find_or_create_by_number(dev, cp.obj_id,
++ cp.variant_type);
++ if (obj) {
++ ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
++ if (!ok)
++ break;
++ if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs2_rd_checkpt_tnodes(obj);
++ } else if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_HARDLINK) {
++ list_add(&obj->hard_links, &hard_list);
++ }
++ } else {
++ ok = 0;
++ }
++ }
++ }
++
++ if (ok)
++ yaffs_link_fixup(dev, &hard_list);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum);
++
++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
++ sizeof(checkpt_sum));
++
++ if (!ok)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum0;
++ u32 checkpt_sum1;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
++
++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
++ sizeof(checkpt_sum1));
++
++ if (!ok)
++ return 0;
++
++ if (checkpt_sum0 != checkpt_sum1)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!yaffs2_checkpt_required(dev)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint write");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 1);
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint device");
++ ok = yaffs2_wr_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint objects");
++ ok = yaffs2_wr_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok)
++ ok = yaffs2_wr_checkpt_sum(dev);
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return dev->is_checkpointed;
++}
++
++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!dev->param.is_yaffs2)
++ ok = 0;
++
++ if (ok && dev->param.skip_checkpt_rd) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint read");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint device");
++ ok = yaffs2_rd_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint objects");
++ ok = yaffs2_rd_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok) {
++ ok = yaffs2_rd_checkpt_sum(dev);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint checksum %d", ok);
++ }
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return ok ? 1 : 0;
++}
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
++{
++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
++ dev->is_checkpointed = 0;
++ yaffs2_checkpt_invalidate_stream(dev);
++ }
++ if (dev->param.sb_dirty_fn)
++ dev->param.sb_dirty_fn(dev);
++}
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "save entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++
++ if (!dev->is_checkpointed) {
++ yaffs2_checkpt_invalidate(dev);
++ yaffs2_wr_checkpt_data(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++ "save exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return dev->is_checkpointed;
++}
++
++int yaffs2_checkpt_restore(struct yaffs_dev *dev)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ retval = yaffs2_rd_checkpt_data(dev);
++
++ if (dev->is_checkpointed) {
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return retval;
++}
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
++{
++ /* if new_size > old_file_size.
++ * We're going to be writing a hole.
++ * If the hole is small then write zeros otherwise write a start
++ * of hole marker.
++ */
++ loff_t old_file_size;
++ loff_t increase;
++ int small_hole;
++ int result = YAFFS_OK;
++ struct yaffs_dev *dev = NULL;
++ u8 *local_buffer = NULL;
++ int small_increase_ok = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ dev = obj->my_dev;
++
++ /* Bail out if not yaffs2 mode */
++ if (!dev->param.is_yaffs2)
++ return YAFFS_OK;
++
++ old_file_size = obj->variant.file_variant.file_size;
++
++ if (new_size <= old_file_size)
++ return YAFFS_OK;
++
++ increase = new_size - old_file_size;
++
++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
++ small_hole = 1;
++ else
++ small_hole = 0;
++
++ if (small_hole)
++ local_buffer = yaffs_get_temp_buffer(dev);
++
++ if (local_buffer) {
++ /* fill hole with zero bytes */
++ loff_t pos = old_file_size;
++ int this_write;
++ int written;
++ memset(local_buffer, 0, dev->data_bytes_per_chunk);
++ small_increase_ok = 1;
++
++ while (increase > 0 && small_increase_ok) {
++ this_write = increase;
++ if (this_write > dev->data_bytes_per_chunk)
++ this_write = dev->data_bytes_per_chunk;
++ written =
++ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
++ 0);
++ if (written == this_write) {
++ pos += this_write;
++ increase -= this_write;
++ } else {
++ small_increase_ok = 0;
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++
++ /* If out of space then reverse any chunks we've added */
++ if (!small_increase_ok)
++ yaffs_resize_file_down(obj, old_file_size);
++ }
++
++ if (!small_increase_ok &&
++ obj->parent &&
++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
++ /* Write a hole start header with the old file size */
++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
++ }
++
++ return result;
++}
++
++struct yaffs_block_index {
++ int seq;
++ int block;
++};
++
++static int yaffs2_ybicmp(const void *a, const void *b)
++{
++ int aseq = ((struct yaffs_block_index *)a)->seq;
++ int bseq = ((struct yaffs_block_index *)b)->seq;
++ int ablock = ((struct yaffs_block_index *)a)->block;
++ int bblock = ((struct yaffs_block_index *)b)->block;
++
++ if (aseq == bseq)
++ return ablock - bblock;
++
++ return aseq - bseq;
++}
++
++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int blk, int chunk_in_block,
++ int *found_chunks,
++ u8 *chunk_data,
++ struct list_head *hard_list,
++ int summary_available)
++{
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int equiv_id;
++ loff_t file_size;
++ int is_shrink;
++ int is_unlinked;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++ int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
++ struct yaffs_file_var *file_var;
++ struct yaffs_hardlink_var *hl_var;
++ struct yaffs_symlink_var *sl_var;
++
++ if (summary_available) {
++ result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
++ tags.seq_number = bi->seq_number;
++ }
++
++ if (!summary_available || tags.obj_id == 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
++ dev->tags_used++;
++ } else {
++ dev->summary_used++;
++ }
++
++ /* Let's have a good look at this chunk... */
++
++ if (!tags.chunk_used) {
++ /* An unassigned chunk in the block.
++ * If there are used chunks after this one, then
++ * it is a chunk that was skipped due to failing
++ * the erased check. Just skip it so that it can
++ * be deleted.
++ * But, more typically, We get here when this is
++ * an unallocated chunk and his means that
++ * either the block is empty or this is the one
++ * being allocated from
++ */
++
++ if (*found_chunks) {
++ /* This is a chunk that was skipped due
++ * to failing the erased check */
++ } else if (chunk_in_block == 0) {
++ /* We're looking at the first chunk in
++ * the block so the block is unused */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ if (dev->seq_number == bi->seq_number) {
++ /* Allocating from this block*/
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, chunk_in_block);
++
++ bi->block_state =
++ YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = chunk_in_block;
++ dev->alloc_block_finder = blk;
++ } else {
++ /* This is a partially written block
++ * that is not the current
++ * allocation block.
++ */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Partially written block %d detected. gc will fix this.",
++ blk);
++ }
++ }
++ }
++
++ dev->n_free_chunks++;
++
++ } else if (tags.ecc_result ==
++ YAFFS_ECC_RESULT_UNFIXED) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Unfixed ECC in chunk(%d:%d), chunk ignored",
++ blk, chunk_in_block);
++ dev->n_free_chunks++;
++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
++ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
++ tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
++ (tags.chunk_id > 0 &&
++ tags.n_bytes > dev->data_bytes_per_chunk) ||
++ tags.seq_number != bi->seq_number) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
++ blk, chunk_in_block, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++ dev->n_free_chunks++;
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ loff_t endpos;
++ loff_t chunk_base = (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk;
++
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!in)
++ /* Out of memory */
++ alloc_failed = 1;
++
++ if (in &&
++ in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
++ chunk_base < in->variant.file_variant.shrink_size) {
++ /* This has not been invalidated by
++ * a resize */
++ if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
++ chunk, -1))
++ alloc_failed = 1;
++
++ /* File size is calculated by looking at
++ * the data chunks if we have not
++ * seen an object header yet.
++ * Stop this practice once we find an
++ * object header.
++ */
++ endpos = chunk_base + tags.n_bytes;
++
++ if (!in->valid &&
++ in->variant.file_variant.scanned_size < endpos) {
++ in->variant.file_variant.
++ scanned_size = endpos;
++ in->variant.file_variant.
++ file_size = endpos;
++ }
++ } else if (in) {
++ /* This chunk has been invalidated by a
++ * resize, or a past file deletion
++ * so delete the chunk*/
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make
++ * the object
++ */
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ oh = NULL;
++ in = NULL;
++
++ if (tags.extra_available) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ tags.extra_obj_type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ if (!in ||
++ (!in->valid && dev->param.disable_lazy_load) ||
++ tags.extra_shadows ||
++ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
++
++ /* If we don't have valid info then we
++ * need to read the chunk
++ * TODO In future we can probably defer
++ * reading the chunk and living with
++ * invalid data until needed.
++ */
++
++ result = yaffs_rd_chunk_tags_nand(dev,
++ chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ if (dev->param.inband_tags) {
++ /* Fix up the header if they got
++ * corrupted by inband tags */
++ oh->shadows_obj =
++ oh->inband_shadowed_obj_id;
++ oh->is_shrink =
++ oh->inband_is_shrink;
++ }
++
++ if (!in) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id, oh->type);
++ if (!in)
++ alloc_failed = 1;
++ }
++ }
++
++ if (!in) {
++ /* TODO Hoosterman we have a problem! */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
++ tags.obj_id, chunk);
++ return YAFFS_FAIL;
++ }
++
++ if (in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate that will be
++ * discarded, but we first have to suck
++ * out resize info if it is a file.
++ */
++ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
++ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
++ (tags.extra_available &&
++ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ )) {
++ loff_t this_size = (oh) ?
++ yaffs_oh_to_size(oh) :
++ tags.extra_file_size;
++ u32 parent_obj_id = (oh) ?
++ oh->parent_obj_id :
++ tags.extra_parent_id;
++
++ is_shrink = (oh) ?
++ oh->is_shrink :
++ tags.extra_is_shrink;
++
++ /* If it is deleted (unlinked
++ * at start also means deleted)
++ * we treat the file size as
++ * being zeroed at this point.
++ */
++ if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
++ parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
++ this_size = 0;
++ is_shrink = 1;
++ }
++
++ if (is_shrink &&
++ in->variant.file_variant.shrink_size >
++ this_size)
++ in->variant.file_variant.shrink_size =
++ this_size;
++
++ if (is_shrink)
++ bi->has_shrink_hdr = 1;
++ }
++ /* Use existing - destroy this one. */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++
++ if (!in->valid && in->variant_type !=
++ (oh ? oh->type : tags.extra_obj_type)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
++ oh ? oh->type : tags.extra_obj_type,
++ in->variant_type, tags.obj_id,
++ chunk);
++ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
++ }
++
++ if (!in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++
++ if (oh) {
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->lazy_loaded = 0;
++ } else {
++ in->lazy_loaded = 1;
++ }
++ in->hdr_chunk = chunk;
++
++ } else if (!in->valid) {
++ /* we need to load this info */
++ in->valid = 1;
++ in->hdr_chunk = chunk;
++ if (oh) {
++ in->variant_type = oh->type;
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++
++ if (oh->shadows_obj > 0)
++ yaffs_handle_shadowed_obj(dev,
++ oh->shadows_obj, 1);
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ parent = yaffs_find_or_create_by_number(dev,
++ oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = yaffs_oh_to_size(oh);
++ is_shrink = oh->is_shrink;
++ equiv_id = oh->equiv_id;
++ } else {
++ in->variant_type = tags.extra_obj_type;
++ parent = yaffs_find_or_create_by_number(dev,
++ tags.extra_parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = tags.extra_file_size;
++ is_shrink = tags.extra_is_shrink;
++ equiv_id = tags.extra_equiv_id;
++ in->lazy_loaded = 1;
++ }
++ in->dirty = 0;
++
++ if (!parent)
++ alloc_failed = 1;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ if (parent &&
++ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * Trying to use a non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++ yaffs_add_obj_to_dir(parent, in);
++
++ is_unlinked = (parent == dev->del_dir) ||
++ (parent == dev->unlinked_dir);
++
++ if (is_shrink)
++ /* Mark the block */
++ bi->has_shrink_hdr = 1;
++
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent
++ * object is scanned we put them all in a list.
++ * After scanning is complete, we should have all the
++ * objects, so we run through this list and fix up all
++ * the chains.
++ */
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ file_var = &in->variant.file_variant;
++ if (file_var->scanned_size < file_size) {
++ /* This covers the case where the file
++ * size is greater than the data held.
++ * This will happen if the file is
++ * resized to be larger than its
++ * current data extents.
++ */
++ file_var->file_size = file_size;
++ file_var->scanned_size = file_size;
++ }
++
++ if (file_var->shrink_size > file_size)
++ file_var->shrink_size = file_size;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ hl_var = &in->variant.hardlink_variant;
++ if (!is_unlinked) {
++ hl_var->equiv_id = equiv_id;
++ list_add(&in->hard_links, hard_list);
++ }
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ sl_var = &in->variant.symlink_variant;
++ if (oh) {
++ sl_var->alias =
++ yaffs_clone_str(oh->alias);
++ if (!sl_var->alias)
++ alloc_failed = 1;
++ }
++ break;
++ }
++ }
++ }
++ return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
++}
++
++int yaffs2_scan_backwards(struct yaffs_dev *dev)
++{
++ int blk;
++ int block_iter;
++ int start_iter;
++ int end_iter;
++ int n_to_scan = 0;
++ enum yaffs_block_state state;
++ int c;
++ int deleted;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ u8 *chunk_data;
++ int found_chunks;
++ int alloc_failed = 0;
++ struct yaffs_block_index *block_index = NULL;
++ int alt_block_index = 0;
++ int summary_available;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ block_index =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
++
++ if (!block_index) {
++ block_index =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_index));
++ alt_block_index = 1;
++ }
++
++ if (!block_index) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards() could not allocate block index!"
++ );
++ return YAFFS_FAIL;
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, bi->block_state, seq_number);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ dev->blocks_in_checkpt++;
++
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ } else if (bi->block_state ==
++ YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* Determine the highest sequence number */
++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++ block_index[n_to_scan].seq = seq_number;
++ block_index[n_to_scan].block = blk;
++ n_to_scan++;
++ if (seq_number >= dev->seq_number)
++ dev->seq_number = seq_number;
++ } else {
++ /* TODO: Nasty sequence number! */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Block scanning block %d has bad sequence number %d",
++ blk, seq_number);
++ }
++ }
++ bi++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
++
++ cond_resched();
++
++ /* Sort the blocks by sequence number */
++ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
++ yaffs2_ybicmp, NULL);
++
++ cond_resched();
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "...done");
++
++ /* Now scan the blocks looking at the data. */
++ start_iter = 0;
++ end_iter = n_to_scan - 1;
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
++
++ /* For each block.... backwards */
++ for (block_iter = end_iter;
++ !alloc_failed && block_iter >= start_iter;
++ block_iter--) {
++ /* Cooperative multitasking! This loop can run for so
++ long that watchdog timers expire. */
++ cond_resched();
++
++ /* get the block to scan in the correct order */
++ blk = block_index[block_iter].block;
++ bi = yaffs_get_block_info(dev, blk);
++ deleted = 0;
++
++ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
++
++ /* For each chunk in each block that needs scanning.... */
++ found_chunks = 0;
++ if (summary_available)
++ c = dev->chunks_per_summary - 1;
++ else
++ c = dev->param.chunks_per_block - 1;
++
++ for (/* c is already initialised */;
++ !alloc_failed && c >= 0 &&
++ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
++ c--) {
++ /* Scan backwards...
++ * Read the tags and decide what to do
++ */
++ if (yaffs2_scan_chunk(dev, bi, blk, c,
++ &found_chunks, chunk_data,
++ &hard_list, summary_available) ==
++ YAFFS_FAIL)
++ alloc_failed = 1;
++ }
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning, then the block
++ * is fully allocated. */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_block_became_dirty(dev, blk);
++ }
++ }
++
++ yaffs_skip_rest_of_block(dev);
++
++ if (alt_block_index)
++ vfree(block_index);
++ else
++ kfree(block_index);
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++ yaffs_link_fixup(dev, &hard_list);
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.12.20/fs/yaffs2/yaffs_yaffs2.h
+--- linux-3.12.20.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yaffs_yaffs2.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS2_H__
++#define __YAFFS_YAFFS2_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi);
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
++int yaffs2_checkpt_required(struct yaffs_dev *dev);
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
++int yaffs2_checkpt_save(struct yaffs_dev *dev);
++int yaffs2_checkpt_restore(struct yaffs_dev *dev);
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
++int yaffs2_scan_backwards(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.12.20.orig/fs/yaffs2/yportenv.h linux-3.12.20/fs/yaffs2/yportenv.h
+--- linux-3.12.20.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.12.20/fs/yaffs2/yportenv.h 2014-05-17 11:28:49.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#ifdef YAFFS_OUT_OF_TREE
++#include "moduleconfig.h"
++#endif
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/xattr.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/sort.h>
++#include <linux/bitops.h>
++
++/* These type wrappings are used to support Unicode names in WinCE. */
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#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 compile_time_assertion(assertion) \
++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++
++#define yaffs_printf(msk, fmt, ...) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
++
++#define yaffs_trace(msk, fmt, ...) do { \
++ if (yaffs_trace_mask & (msk)) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
++} while (0)
++
++
++#endif
diff --git a/target/linux/patches/3.11.10/zlib-inflate.patch b/target/linux/patches/3.12.20/zlib-inflate.patch
index 58e1f6d21..58e1f6d21 100644
--- a/target/linux/patches/3.11.10/zlib-inflate.patch
+++ b/target/linux/patches/3.12.20/zlib-inflate.patch
diff --git a/target/linux/patches/3.13.11/yaffs2.patch b/target/linux/patches/3.13.11/yaffs2.patch
new file mode 100644
index 000000000..2073feb52
--- /dev/null
+++ b/target/linux/patches/3.13.11/yaffs2.patch
@@ -0,0 +1,16547 @@
+diff -Nur linux-3.13.11.orig/fs/Kconfig linux-3.13.11/fs/Kconfig
+--- linux-3.13.11.orig/fs/Kconfig 2014-04-23 01:49:33.000000000 +0200
++++ linux-3.13.11/fs/Kconfig 2014-05-17 08:34:57.000000000 +0200
+@@ -193,6 +193,7 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Nur linux-3.13.11.orig/fs/Makefile linux-3.13.11/fs/Makefile
+--- linux-3.13.11.orig/fs/Makefile 2014-04-23 01:49:33.000000000 +0200
++++ linux-3.13.11/fs/Makefile 2014-05-17 08:34:57.000000000 +0200
+@@ -126,3 +126,4 @@
+ obj-$(CONFIG_CEPH_FS) += ceph/
+ obj-$(CONFIG_PSTORE) += pstore/
+ obj-$(CONFIG_EFIVAR_FS) += efivarfs/
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
+diff -Nur linux-3.13.11.orig/fs/yaffs2/Kconfig linux-3.13.11/fs/yaffs2/Kconfig
+--- linux-3.13.11.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/Kconfig 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,171 @@
++#
++# yaffs file system configurations
++#
++
++config YAFFS_FS
++ tristate "yaffs2 file system support"
++ default n
++ depends on MTD_BLOCK
++ select YAFFS_YAFFS1
++ select YAFFS_YAFFS2
++ help
++ yaffs2, or Yet Another Flash File System, is a file 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
++ in yaffs_mtdif1.c.
++
++ 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_TAGS_ECC
++ bool "Disable yaffs from doing ECC on tags by default"
++ depends on YAFFS_FS && YAFFS_YAFFS2
++ default n
++ help
++ This defaults yaffs to using its own ECC calculations on tags instead of
++ just relying on the MTD.
++ This behavior can also be overridden with tags_ecc_on and
++ tags_ecc_off mount options.
++
++ 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_EMPTY_LOST_AND_FOUND
++ bool "Empty lost and found on boot"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is enabled then the contents of lost and found is
++ automatically dumped at mount.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++ bool "Disable yaffs2 block refreshing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then block refreshing is disabled.
++ Block refreshing infrequently refreshes the oldest block in
++ a yaffs2 file system. This mechanism helps to refresh flash to
++ mitigate against data loss. This is particularly useful for MLC.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++ bool "Disable yaffs2 background processing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then background processing is disabled.
++ Background processing makes many foreground activities faster.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BAD_BLOCK_MARKING
++ bool "Disable yaffs2 bad block marking"
++ depends on YAFFS_FS
++ default n
++ help
++ Useful during early flash bring up to prevent problems causing
++ lots of bad block marking.
++
++ If unsure, say N.
++
++config YAFFS_XATTR
++ bool "Enable yaffs2 xattr support"
++ depends on YAFFS_FS
++ default y
++ help
++ If this is set then yaffs2 will provide xattr support.
++ If unsure, say Y.
+diff -Nur linux-3.13.11.orig/fs/yaffs2/Makefile linux-3.13.11/fs/yaffs2/Makefile
+--- linux-3.13.11.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/Makefile 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,18 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
++yaffs-y += yaffs_mtdif.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_summary.o
++yaffs-y += yaffs_verify.o
++
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_allocator.c linux-3.13.11/fs/yaffs2/yaffs_allocator.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_allocator.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,357 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++/*
++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
++ * of approx 100 objects that are themn allocated singly.
++ * This is basically a simplified slab allocator.
++ *
++ * We don't use the Linux slab allocator because slab does not allow
++ * us to dump all the objects in one hit when we do a umount and tear
++ * down all the tnodes and objects. slab requires that we first free
++ * the individual objects.
++ *
++ * Once yaffs has been mainlined I shall try to motivate for a change
++ * to slab to provide the extra features we need here.
++ */
++
++struct yaffs_tnode_list {
++ struct yaffs_tnode_list *next;
++ struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++ struct yaffs_obj_list *next;
++ struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++ int n_tnodes_created;
++ struct yaffs_tnode *free_tnodes;
++ int n_free_tnodes;
++ struct yaffs_tnode_list *alloc_tnode_list;
++
++ int n_obj_created;
++ struct list_head free_objs;
++ int n_free_objects;
++
++ struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->alloc_tnode_list) {
++ tmp = allocator->alloc_tnode_list->next;
++
++ kfree(allocator->alloc_tnode_list->tnodes);
++ kfree(allocator->alloc_tnode_list);
++ allocator->alloc_tnode_list = tmp;
++ }
++
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->alloc_tnode_list = NULL;
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ int i;
++ struct yaffs_tnode *new_tnodes;
++ u8 *mem;
++ struct yaffs_tnode *curr;
++ struct yaffs_tnode *next;
++ struct yaffs_tnode_list *tnl;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_tnodes < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
++ mem = (u8 *) new_tnodes;
++
++ if (!new_tnodes) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: Could not allocate Tnodes");
++ return YAFFS_FAIL;
++ }
++
++ /* New hookup for wide tnodes */
++ for (i = 0; i < n_tnodes - 1; i++) {
++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++ curr->internal[0] = next;
++ }
++
++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++ curr->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++ allocator->n_free_tnodes += n_tnodes;
++ allocator->n_tnodes_created += n_tnodes;
++
++ /* Now add this bunch of tnodes to a list for freeing up.
++ * NB If we can't add this to the management list it isn't fatal
++ * but it just means we can't free this bunch of tnodes later.
++ */
++ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
++ if (!tnl) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Could not add tnodes to management list");
++ return YAFFS_FAIL;
++ } else {
++ tnl->tnodes = new_tnodes;
++ tnl->next = allocator->alloc_tnode_list;
++ allocator->alloc_tnode_list = tnl;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
++
++ return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode *tn = NULL;
++
++ if (!allocator) {
++ BUG();
++ return NULL;
++ }
++
++ /* If there are none left make more */
++ if (!allocator->free_tnodes)
++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++ if (allocator->free_tnodes) {
++ tn = allocator->free_tnodes;
++ allocator->free_tnodes = allocator->free_tnodes->internal[0];
++ allocator->n_free_tnodes--;
++ }
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ if (tn) {
++ tn->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = tn;
++ allocator->n_free_tnodes++;
++ }
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++/*--------------- yaffs_obj alloaction ------------------------
++ *
++ * Free yaffs_objs are stored in a list using obj->siblings.
++ * The blocks of allocated objects are stored in a linked list.
++ */
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->allocated_obj_list = NULL;
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ struct yaffs_obj_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->allocated_obj_list) {
++ tmp = allocator->allocated_obj_list->next;
++ kfree(allocator->allocated_obj_list->objects);
++ kfree(allocator->allocated_obj_list);
++ allocator->allocated_obj_list = tmp;
++ }
++
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++ allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ int i;
++ struct yaffs_obj *new_objs;
++ struct yaffs_obj_list *list;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_obj < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
++ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
++
++ if (!new_objs || !list) {
++ kfree(new_objs);
++ new_objs = NULL;
++ kfree(list);
++ list = NULL;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Could not allocate more objects");
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++ for (i = 0; i < n_obj; i++)
++ list_add(&new_objs[i].siblings, &allocator->free_objs);
++
++ allocator->n_free_objects += n_obj;
++ allocator->n_obj_created += n_obj;
++
++ /* Now add this bunch of Objects to a list for freeing up. */
++
++ list->objects = new_objs;
++ list->next = allocator->allocated_obj_list;
++ allocator->allocated_obj_list = list;
++
++ return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = NULL;
++ struct list_head *lh;
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return obj;
++ }
++
++ /* If there are none left make more */
++ if (list_empty(&allocator->free_objs))
++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++ if (!list_empty(&allocator->free_objs)) {
++ lh = allocator->free_objs.next;
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ list_del_init(lh);
++ allocator->n_free_objects--;
++ }
++
++ return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ /* Link into the free list. */
++ list_add(&obj->siblings, &allocator->free_objs);
++ allocator->n_free_objects++;
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++
++ if (!dev->allocator) {
++ BUG();
++ return;
++ }
++
++ yaffs_deinit_raw_tnodes(dev);
++ yaffs_deinit_raw_objs(dev);
++ kfree(dev->allocator);
++ dev->allocator = NULL;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator;
++
++ if (dev->allocator) {
++ BUG();
++ return;
++ }
++
++ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
++ if (allocator) {
++ dev->allocator = allocator;
++ yaffs_init_raw_tnodes(dev);
++ yaffs_init_raw_objs(dev);
++ }
++}
++
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_allocator.h linux-3.13.11/fs/yaffs2/yaffs_allocator.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_allocator.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_attribs.c linux-3.13.11/fs/yaffs2/yaffs_attribs.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_attribs.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return from_kuid(&init_user_ns, iattr->ia_uid);
++}
++
++static inline gid_t ia_gid_read(const struct iattr *iattr)
++{
++ return from_kgid(&init_user_ns, iattr->ia_gid);
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = make_kuid(&init_user_ns, uid);
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = make_kgid(&init_user_ns, gid);
++}
++#else
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return iattr->ia_uid;
++}
++
++static inline gid_t ia_gid_read(const struct iattr *inode)
++{
++ return iattr->ia_gid;
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = uid;
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = gid;
++}
++#endif
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++ obj->yst_uid = oh->yst_uid;
++ obj->yst_gid = oh->yst_gid;
++ obj->yst_atime = oh->yst_atime;
++ obj->yst_mtime = oh->yst_mtime;
++ obj->yst_ctime = oh->yst_ctime;
++ obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++ oh->yst_uid = obj->yst_uid;
++ oh->yst_gid = obj->yst_gid;
++ oh->yst_atime = obj->yst_atime;
++ oh->yst_mtime = obj->yst_mtime;
++ oh->yst_ctime = obj->yst_ctime;
++ oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++ obj->yst_mtime = Y_CURRENT_TIME;
++ if (do_a)
++ obj->yst_atime = obj->yst_mtime;
++ if (do_c)
++ obj->yst_ctime = obj->yst_mtime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++ yaffs_load_current_time(obj, 1, 1);
++ obj->yst_rdev = rdev;
++ obj->yst_uid = uid;
++ obj->yst_gid = gid;
++}
++
++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++ YCHAR *alias = NULL;
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return obj->variant.file_variant.file_size;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = obj->variant.symlink_variant.alias;
++ if (!alias)
++ return 0;
++ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++ default:
++ return 0;
++ }
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = attr->ia_valid;
++
++ if (valid & ATTR_MODE)
++ obj->yst_mode = attr->ia_mode;
++ if (valid & ATTR_UID)
++ obj->yst_uid = ia_uid_read(attr);
++ if (valid & ATTR_GID)
++ obj->yst_gid = ia_gid_read(attr);
++
++ if (valid & ATTR_ATIME)
++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++ if (valid & ATTR_CTIME)
++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++ if (valid & ATTR_MTIME)
++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++ if (valid & ATTR_SIZE)
++ yaffs_resize_file(obj, attr->ia_size);
++
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = 0;
++
++ attr->ia_mode = obj->yst_mode;
++ valid |= ATTR_MODE;
++ ia_uid_write(attr, obj->yst_uid);
++ valid |= ATTR_UID;
++ ia_gid_write(attr, obj->yst_gid);
++ valid |= ATTR_GID;
++
++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++ valid |= ATTR_ATIME;
++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++ valid |= ATTR_CTIME;
++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++ valid |= ATTR_MTIME;
++
++ attr->ia_size = yaffs_get_file_size(obj);
++ valid |= ATTR_SIZE;
++
++ attr->ia_valid = valid;
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_attribs.h linux-3.13.11/fs/yaffs2/yaffs_attribs.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_attribs.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_bitmap.c linux-3.13.11/fs/yaffs2/yaffs_bitmap.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_bitmap.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "BlockBits block %d is not valid",
++ blk);
++ BUG();
++ }
++ return dev->chunk_bits +
++ (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++ chunk < 0 || chunk >= dev->param.chunks_per_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Chunk Id (%d:%d) invalid",
++ blk, chunk);
++ BUG();
++ }
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++) {
++ if (*blk_bits)
++ return 1;
++ blk_bits++;
++ }
++ return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++ int n = 0;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
++ n += hweight8(*blk_bits);
++
++ return n;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_bitmap.h linux-3.13.11/fs/yaffs2/yaffs_bitmap.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_bitmap.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.13.11/fs/yaffs2/yaffs_checkptrw.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_checkptrw.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,474 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++struct yaffs_checkpt_chunk_hdr {
++ int version;
++ int seq;
++ u32 sum;
++ u32 xor;
++} ;
++
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++static int apply_block_offset(struct yaffs_dev *dev, int block)
++{
++ return block - dev->block_offset;
++}
++
++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ hdr.version = YAFFS_CHECKPOINT_VERSION;
++ hdr.seq = dev->checkpt_page_seq;
++ hdr.sum = dev->checkpt_sum;
++ hdr.xor = dev->checkpt_xor;
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
++}
++
++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ return hdr.version == YAFFS_CHECKPOINT_VERSION &&
++ hdr.seq == dev->checkpt_page_seq &&
++ hdr.sum == dev->checkpt_sum &&
++ hdr.xor == dev->checkpt_xor;
++}
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpt blocks_avail = %d", blocks_avail);
++
++ return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (!dev->drv.drv_erase_fn)
++ return 0;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checking blocks %d to %d",
++ dev->internal_start_block, dev->internal_end_block);
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ int offset_i = apply_block_offset(dev, i);
++ int result;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "erasing checkpt block %d", i);
++
++ dev->n_erasures++;
++
++ result = dev->drv.drv_erase_fn(dev, offset_i);
++ if(result) {
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ dev->n_free_chunks +=
++ dev->param.chunks_per_block;
++ } else {
++ dev->drv.drv_mark_bad_fn(dev, offset_i);
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ }
++ }
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++ int i;
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block: erased %d reserved %d avail %d next %d ",
++ dev->n_erased_blocks, dev->param.n_reserved_blocks,
++ blocks_avail, dev->checkpt_next_block);
++
++ if (dev->checkpt_next_block >= 0 &&
++ dev->checkpt_next_block <= dev->internal_end_block &&
++ blocks_avail > 0) {
++
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev, i);
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ dev->checkpt_next_block = i + 1;
++ dev->checkpt_cur_block = i;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block %d", i);
++ return;
++ }
++ }
++ }
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_ext_tags tags;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: start: blocks %d next %d",
++ dev->blocks_in_checkpt, dev->checkpt_next_block);
++
++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ int chunk = i * dev->param.chunks_per_block;
++ enum yaffs_block_state state;
++ u32 seq;
++
++ dev->tagger.read_chunk_tags_fn(dev,
++ apply_chunk_offset(dev, chunk),
++ NULL, &tags);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
++ i, (int) state,
++ tags.obj_id, tags.seq_number,
++ tags.ecc_result);
++
++ if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ continue;
++
++ dev->tagger.query_block_fn(dev,
++ apply_block_offset(dev, i),
++ &state, &seq);
++ if (state == YAFFS_BLOCK_STATE_DEAD)
++ continue;
++
++ /* Right kind of block */
++ dev->checkpt_next_block = tags.obj_id;
++ dev->checkpt_cur_block = i;
++ dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
++ dev->blocks_in_checkpt++;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "found checkpt block %d", i);
++ return;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++ int i;
++
++ dev->checkpt_open_write = writing;
++
++ /* Got the functions we need? */
++ if (!dev->tagger.write_chunk_tags_fn ||
++ !dev->tagger.read_chunk_tags_fn ||
++ !dev->drv.drv_erase_fn ||
++ !dev->drv.drv_mark_bad_fn)
++ return 0;
++
++ if (writing && !yaffs2_checkpt_space_ok(dev))
++ return 0;
++
++ if (!dev->checkpt_buffer)
++ dev->checkpt_buffer =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ dev->checkpt_page_seq = 0;
++ dev->checkpt_byte_count = 0;
++ dev->checkpt_sum = 0;
++ dev->checkpt_xor = 0;
++ dev->checkpt_cur_block = -1;
++ dev->checkpt_cur_chunk = -1;
++ dev->checkpt_next_block = dev->internal_start_block;
++
++ if (writing) {
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++ yaffs2_checkpt_init_chunk_hdr(dev);
++ return yaffs_checkpt_erase(dev);
++ }
++
++ /* Opening for a read */
++ /* Set to a value that will kick off a read */
++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++ /* A checkpoint block list of 1 checkpoint block per 16 block is
++ * (hopefully) going to be way more than we need */
++ dev->blocks_in_checkpt = 0;
++ dev->checkpt_max_blocks =
++ (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
++ dev->checkpt_block_list =
++ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
++
++ if (!dev->checkpt_block_list)
++ return 0;
++
++ for (i = 0; i < dev->checkpt_max_blocks; i++)
++ dev->checkpt_block_list[i] = -1;
++
++ return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++ u32 composite_sum;
++
++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
++ *sum = composite_sum;
++ return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++ int chunk;
++ int offset_chunk;
++ struct yaffs_ext_tags tags;
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_erased_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0)
++ return 0;
++
++ tags.is_deleted = 0;
++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
++ tags.chunk_id = dev->checkpt_page_seq + 1;
++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++ tags.n_bytes = dev->data_bytes_per_chunk;
++ if (dev->checkpt_cur_chunk == 0) {
++ /* First chunk we write for the block? Set block state to
++ checkpoint */
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, dev->checkpt_cur_block);
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ dev->blocks_in_checkpt++;
++ }
++
++ chunk =
++ dev->checkpt_cur_block * dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
++ tags.obj_id, tags.chunk_id);
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++
++ dev->n_page_writes++;
++
++ dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
++ dev->checkpt_buffer, &tags);
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++ dev->checkpt_cur_chunk = 0;
++ dev->checkpt_cur_block = -1;
++ }
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++ yaffs2_checkpt_init_chunk_hdr(dev);
++
++
++ return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (!dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++ ok = yaffs2_checkpt_flush_buffer(dev);
++ }
++
++ return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ struct yaffs_ext_tags tags;
++ int chunk;
++ int offset_chunk;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0) {
++ ok = 0;
++ break;
++ }
++
++ chunk = dev->checkpt_cur_block *
++ dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++ dev->n_page_reads++;
++
++ /* read in the next chunk */
++ dev->tagger.read_chunk_tags_fn(dev,
++ offset_chunk,
++ dev->checkpt_buffer,
++ &tags);
++
++ if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++ ok = 0;
++ break;
++ }
++ if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
++ ok = 0;
++ break;
++ }
++
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++
++ if (dev->checkpt_cur_chunk >=
++ dev->param.chunks_per_block)
++ dev->checkpt_cur_block = -1;
++
++ }
++
++ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++ }
++
++ return i;
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->checkpt_open_write) {
++ if (dev->checkpt_byte_offs !=
++ sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
++ yaffs2_checkpt_flush_buffer(dev);
++ } else if (dev->checkpt_block_list) {
++ for (i = 0;
++ i < dev->blocks_in_checkpt &&
++ dev->checkpt_block_list[i] >= 0; i++) {
++ int blk = dev->checkpt_block_list[i];
++ struct yaffs_block_info *bi = NULL;
++
++ if (dev->internal_start_block <= blk &&
++ blk <= dev->internal_end_block)
++ bi = yaffs_get_block_info(dev, blk);
++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ }
++ kfree(dev->checkpt_block_list);
++ dev->checkpt_block_list = NULL;
++ }
++
++ dev->n_free_chunks -=
++ dev->blocks_in_checkpt * dev->param.chunks_per_block;
++ dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
++ dev->checkpt_byte_count);
++
++ if (dev->checkpt_buffer) {
++ /* free the buffer */
++ kfree(dev->checkpt_buffer);
++ dev->checkpt_buffer = NULL;
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++ /* Erase the checkpoint data */
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint invalidate of %d blocks",
++ dev->blocks_in_checkpt);
++
++ return yaffs_checkpt_erase(dev);
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.13.11/fs/yaffs2/yaffs_checkptrw.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_checkptrw.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_ecc.c linux-3.13.11/fs/yaffs2/yaffs_ecc.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_ecc.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,281 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
++ * such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
++ * and therefore this bytes influence on the line parity.
++ */
++
++static const unsigned char column_parity_table[] = {
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned char line_parity = 0;
++ unsigned char line_parity_prime = 0;
++ unsigned char t;
++ unsigned char b;
++
++ for (i = 0; i < 256; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) { /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++ }
++
++ ecc[2] = (~col_parity) | 0x03;
++
++ t = 0;
++ if (line_parity & 0x80)
++ t |= 0x80;
++ if (line_parity_prime & 0x80)
++ t |= 0x40;
++ if (line_parity & 0x40)
++ t |= 0x20;
++ if (line_parity_prime & 0x40)
++ t |= 0x10;
++ if (line_parity & 0x20)
++ t |= 0x08;
++ if (line_parity_prime & 0x20)
++ t |= 0x04;
++ if (line_parity & 0x10)
++ t |= 0x02;
++ if (line_parity_prime & 0x10)
++ t |= 0x01;
++ ecc[1] = ~t;
++
++ t = 0;
++ if (line_parity & 0x08)
++ t |= 0x80;
++ if (line_parity_prime & 0x08)
++ t |= 0x40;
++ if (line_parity & 0x04)
++ t |= 0x20;
++ if (line_parity_prime & 0x04)
++ t |= 0x10;
++ if (line_parity & 0x02)
++ t |= 0x08;
++ if (line_parity_prime & 0x02)
++ t |= 0x04;
++ if (line_parity & 0x01)
++ t |= 0x02;
++ if (line_parity_prime & 0x01)
++ t |= 0x01;
++ ecc[0] = ~t;
++
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc)
++{
++ unsigned char d0, d1, d2; /* deltas */
++
++ d0 = read_ecc[0] ^ test_ecc[0];
++ d1 = read_ecc[1] ^ test_ecc[1];
++ d2 = read_ecc[2] ^ test_ecc[2];
++
++ if ((d0 | d1 | d2) == 0)
++ return 0; /* no error */
++
++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++ /* Single bit (recoverable) error in data */
++
++ unsigned byte;
++ unsigned bit;
++
++ bit = byte = 0;
++
++ if (d1 & 0x80)
++ byte |= 0x80;
++ if (d1 & 0x20)
++ byte |= 0x40;
++ if (d1 & 0x08)
++ byte |= 0x20;
++ if (d1 & 0x02)
++ byte |= 0x10;
++ if (d0 & 0x80)
++ byte |= 0x08;
++ if (d0 & 0x20)
++ byte |= 0x04;
++ if (d0 & 0x08)
++ byte |= 0x02;
++ if (d0 & 0x02)
++ byte |= 0x01;
++
++ if (d2 & 0x80)
++ bit |= 0x04;
++ if (d2 & 0x20)
++ bit |= 0x02;
++ if (d2 & 0x08)
++ bit |= 0x01;
++
++ data[byte] ^= (1 << bit);
++
++ return 1; /* Corrected the error */
++ }
++
++ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
++ /* Reccoverable error in ecc */
++
++ read_ecc[0] = test_ecc[0];
++ read_ecc[1] = test_ecc[1];
++ read_ecc[2] = test_ecc[2];
++
++ return 1; /* Corrected the error */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc_other)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned line_parity = 0;
++ unsigned line_parity_prime = 0;
++ unsigned char b;
++
++ for (i = 0; i < n_bytes; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) {
++ /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++
++ }
++
++ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++ ecc_other->line_parity = line_parity;
++ ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc)
++{
++ unsigned char delta_col; /* column parity delta */
++ unsigned delta_line; /* line parity delta */
++ unsigned delta_line_prime; /* line parity delta */
++ unsigned bit;
++
++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++ delta_line_prime =
++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++ if ((delta_col | delta_line | delta_line_prime) == 0)
++ return 0; /* no error */
++
++ if (delta_line == ~delta_line_prime &&
++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++ /* Single bit (recoverable) error in data */
++
++ bit = 0;
++
++ if (delta_col & 0x20)
++ bit |= 0x04;
++ if (delta_col & 0x08)
++ bit |= 0x02;
++ if (delta_col & 0x02)
++ bit |= 0x01;
++
++ if (delta_line >= n_bytes)
++ return -1;
++
++ data[delta_line] ^= (1 << bit);
++
++ return 1; /* corrected */
++ }
++
++ if ((hweight32(delta_line) +
++ hweight32(delta_line_prime) +
++ hweight8(delta_col)) == 1) {
++ /* Reccoverable error in ecc */
++
++ *read_ecc = *test_ecc;
++ return 1; /* corrected */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_ecc.h linux-3.13.11/fs/yaffs2/yaffs_ecc.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_ecc.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data.
++ * Thus, two such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++ unsigned char col_parity;
++ unsigned line_parity;
++ unsigned line_parity_prime;
++};
++
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc);
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.13.11/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_getblockinfo.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++ *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs: get_block_info block %d is not valid",
++ blk);
++ BUG();
++ }
++ return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_guts.c linux-3.13.11/fs/yaffs2/yaffs_guts.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_guts.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,5146 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsmarshall.h"
++#include "yaffs_nand.h"
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Forward declarations */
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve);
++
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size);
++
++/* Function to calculate chunk and offset */
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out)
++{
++ int chunk;
++ u32 offset;
++
++ chunk = (u32) (addr >> dev->chunk_shift);
++
++ if (dev->chunk_div == 1) {
++ /* easy power of 2 case */
++ offset = (u32) (addr & dev->chunk_mask);
++ } else {
++ /* Non power-of-2 case */
++
++ loff_t chunk_base;
++
++ chunk /= dev->chunk_div;
++
++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++ offset = (u32) (addr - chunk_base);
++ }
++
++ *chunk_out = chunk;
++ *offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static inline u32 calc_shifts_ceiling(u32 x)
++{
++ int extra_bits;
++ int shifts;
++
++ shifts = extra_bits = 0;
++
++ while (x > 1) {
++ if (x & 1)
++ extra_bits++;
++ x >>= 1;
++ shifts++;
++ }
++
++ if (extra_bits)
++ shifts++;
++
++ return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static inline u32 calc_shifts(u32 x)
++{
++ u32 shifts;
++
++ shifts = 0;
++
++ if (!x)
++ return 0;
++
++ while (!(x & 1)) {
++ x >>= 1;
++ shifts++;
++ }
++
++ return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++ int i;
++ u8 *buf = (u8 *) 1;
++
++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++ dev->temp_buffer[i].in_use = 0;
++ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ dev->temp_buffer[i].buffer = buf;
++ }
++
++ return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
++{
++ int i;
++
++ dev->temp_in_use++;
++ if (dev->temp_in_use > dev->max_temp)
++ dev->max_temp = dev->temp_in_use;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].in_use == 0) {
++ dev->temp_buffer[i].in_use = 1;
++ return dev->temp_buffer[i].buffer;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
++ /*
++ * If we got here then we have to allocate an unmanaged one
++ * This is not good.
++ */
++
++ dev->unmanaged_buffer_allocs++;
++ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
++{
++ int i;
++
++ dev->temp_in_use--;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].buffer == buffer) {
++ dev->temp_buffer[i].in_use = 0;
++ return;
++ }
++ }
++
++ if (buffer) {
++ /* assume it is an unmanaged one. */
++ yaffs_trace(YAFFS_TRACE_BUFFERS,
++ "Releasing unmanaged temp buffer");
++ kfree(buffer);
++ dev->unmanaged_buffer_deallocs++;
++ }
++
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) data;
++ (void) tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++ if (!bi->gc_prioritise) {
++ bi->gc_prioritise = 1;
++ dev->has_pending_prioritised_gc = 1;
++ bi->chunk_error_strikes++;
++
++ if (bi->chunk_error_strikes > 3) {
++ bi->needs_retiring = 1; /* Too many stikes, so retire */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Block struck out");
++
++ }
++ }
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++ int erased_ok)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs_handle_chunk_error(dev, bi);
++
++ if (erased_ok) {
++ /* Was an actual write failure,
++ * so mark the block for retirement.*/
++ bi->needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d needs retiring", flash_block);
++ }
++
++ /* Delete the chunk */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ * Simple hash function. Needs to have a reasonable spread
++ */
++
++static inline int yaffs_hash_fn(int n)
++{
++ if (n < 0)
++ n = -n;
++ return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++ return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++ return dev->lost_n_found;
++}
++
++/*
++ * Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 *buffer, int n_bytes)
++{
++ /* Horrible, slow implementation */
++ while (n_bytes--) {
++ if (*buffer != 0xff)
++ return 0;
++ buffer++;
++ }
++ return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++ int retval = YAFFS_OK;
++ u8 *data = yaffs_get_temp_buffer(dev);
++ struct yaffs_ext_tags tags;
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++ retval = YAFFS_FAIL;
++
++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
++ tags.chunk_used) {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not erased", nand_chunk);
++ retval = YAFFS_FAIL;
++ }
++
++ yaffs_release_temp_buffer(dev, data);
++
++ return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = YAFFS_OK;
++ struct yaffs_ext_tags temp_tags;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++ temp_tags.obj_id != tags->obj_id ||
++ temp_tags.chunk_id != tags->chunk_id ||
++ temp_tags.n_bytes != tags->n_bytes)
++ retval = YAFFS_FAIL;
++
++ yaffs_release_temp_buffer(dev, buffer);
++
++ return retval;
++}
++
++
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
++{
++ int reserved_chunks;
++ int reserved_blocks = dev->param.n_reserved_blocks;
++ int checkpt_blocks;
++
++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
++
++ reserved_chunks =
++ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
++
++ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
++}
++
++static int yaffs_find_alloc_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_block_info *bi;
++
++ if (dev->n_erased_blocks < 1) {
++ /* Hoosterman we've got a problem.
++ * Can't get space to gc
++ */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no more erased blocks");
++
++ return -1;
++ }
++
++ /* Find an empty block. */
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ dev->alloc_block_finder++;
++ if (dev->alloc_block_finder < dev->internal_start_block
++ || dev->alloc_block_finder > dev->internal_end_block) {
++ dev->alloc_block_finder = dev->internal_start_block;
++ }
++
++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->seq_number++;
++ bi->seq_number = dev->seq_number;
++ dev->n_erased_blocks--;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Allocated block %d, seq %d, %d left" ,
++ dev->alloc_block_finder, dev->seq_number,
++ dev->n_erased_blocks);
++ return dev->alloc_block_finder;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs tragedy: no more erased blocks, but there should have been %d",
++ dev->n_erased_blocks);
++
++ return -1;
++}
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++ struct yaffs_block_info **block_ptr)
++{
++ int ret_val;
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block < 0) {
++ /* Get next block to allocate off */
++ dev->alloc_block = yaffs_find_alloc_block(dev);
++ dev->alloc_page = 0;
++ }
++
++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
++ /* No space unless we're allowed to use the reserve. */
++ return -1;
++ }
++
++ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
++ && dev->alloc_page == 0)
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
++
++ /* Next page please.... */
++ if (dev->alloc_block >= 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++
++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
++ dev->alloc_page;
++ bi->pages_in_use++;
++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
++
++ dev->alloc_page++;
++
++ dev->n_free_chunks--;
++
++ /* If the block is full set the state to full */
++ if (dev->alloc_page >= dev->param.chunks_per_block) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ if (block_ptr)
++ *block_ptr = bi;
++
++ return ret_val;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
++
++ return -1;
++}
++
++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
++{
++ int n;
++
++ n = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ if (dev->alloc_block > 0)
++ n += (dev->param.chunks_per_block - dev->alloc_page);
++
++ return n;
++
++}
++
++/*
++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
++{
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block > 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++ }
++}
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++ const u8 *data,
++ struct yaffs_ext_tags *tags, int use_reserver)
++{
++ int attempts = 0;
++ int write_ok = 0;
++ int chunk;
++
++ yaffs2_checkpt_invalidate(dev);
++
++ do {
++ struct yaffs_block_info *bi = 0;
++ int erased_ok = 0;
++
++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
++ if (chunk < 0) {
++ /* no space */
++ break;
++ }
++
++ /* First check this chunk is erased, if it needs
++ * checking. The checking policy (unless forced
++ * always on) is as follows:
++ *
++ * Check the first page we try to write in a block.
++ * If the check passes then we don't need to check any
++ * more. If the check fails, we check again...
++ * If the block has been erased, we don't need to check.
++ *
++ * However, if the block has been prioritised for gc,
++ * then we think there might be something odd about
++ * this block and stop using it.
++ *
++ * Rationale: We should only ever see chunks that have
++ * not been erased if there was a partially written
++ * chunk due to power loss. This checking policy should
++ * catch that case with very few checks and thus save a
++ * lot of checks that are most likely not needed.
++ *
++ * Mods to the above
++ * If an erase check fails or the write fails we skip the
++ * rest of the block.
++ */
++
++ /* let's give it a try */
++ attempts++;
++
++ if (dev->param.always_check_erased)
++ bi->skip_erased_check = 0;
++
++ if (!bi->skip_erased_check) {
++ erased_ok = yaffs_check_chunk_erased(dev, chunk);
++ if (erased_ok != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs chunk %d was not erased",
++ chunk);
++
++ /* If not erased, delete this one,
++ * skip rest of block and
++ * try another chunk */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++ continue;
++ }
++ }
++
++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
++
++ if (!bi->skip_erased_check)
++ write_ok =
++ yaffs_verify_chunk_written(dev, chunk, data, tags);
++
++ if (write_ok != YAFFS_OK) {
++ /* Clean up aborted write, skip to next block and
++ * try another chunk */
++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
++ continue;
++ }
++
++ bi->skip_erased_check = 1;
++
++ /* Copy the data into the robustification buffer */
++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
++
++ } while (write_ok != YAFFS_OK &&
++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++ if (!write_ok)
++ chunk = -1;
++
++ if (attempts > 1) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs write required %d attempts",
++ attempts);
++ dev->n_retried_writes += (attempts - 1);
++ }
++
++ return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to mark bad and erase block %d",
++ flash_block);
++ } else {
++ struct yaffs_ext_tags tags;
++ int chunk_id =
++ flash_block * dev->param.chunks_per_block;
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ memset(&tags, 0, sizeof(tags));
++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
++ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
++ dev->chunk_offset,
++ buffer,
++ &tags) != YAFFS_OK)
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to write bad block marker to block %d",
++ flash_block);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++ }
++
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ bi->gc_prioritise = 0;
++ bi->needs_retiring = 0;
++
++ dev->n_retired_blocks++;
++}
++
++/*---------------- Name handling functions ------------*/
++
++static u16 yaffs_calc_name_sum(const YCHAR *name)
++{
++ u16 sum = 0;
++ u16 i = 1;
++
++ if (!name)
++ return 0;
++
++ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
++
++ /* 0x1f mask is case insensitive */
++ sum += ((*name) & 0x1f) * i;
++ i++;
++ name++;
++ }
++ return sum;
++}
++
++
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
++{
++ memset(obj->short_name, 0, sizeof(obj->short_name));
++
++ if (name && !name[0]) {
++ yaffs_fix_null_name(obj, obj->short_name,
++ YAFFS_SHORT_NAME_LENGTH);
++ name = obj->short_name;
++ } else if (name &&
++ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
++ YAFFS_SHORT_NAME_LENGTH) {
++ strcpy(obj->short_name, name);
++ }
++
++ obj->sum = yaffs_calc_name_sum(name);
++}
++
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
++ memset(tmp_name, 0, sizeof(tmp_name));
++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_set_obj_name(obj, tmp_name);
++#else
++ yaffs_set_obj_name(obj, oh->name);
++#endif
++}
++
++loff_t yaffs_max_file_size(struct yaffs_dev *dev)
++{
++ if(sizeof(loff_t) < 8)
++ return YAFFS_MAX_FILE_SIZE_32;
++ else
++ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
++
++ if (tn) {
++ memset(tn, 0, dev->tnode_size);
++ dev->n_tnodes++;
++ }
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ yaffs_free_raw_tnode(dev, tn);
++ dev->n_tnodes--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ yaffs_deinit_raw_tnodes_and_objs(dev);
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++}
++
++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos, unsigned val)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 mask;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++ val >>= dev->chunk_grp_bits;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ mask = dev->tnode_mask << bit_in_word;
++
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val << bit_in_word));
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ mask =
++ dev->tnode_mask >> bit_in_word;
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val >> bit_in_word));
++ }
++}
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 val;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ val = map[word_in_map] >> bit_in_word;
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ val |= (map[word_in_map] << bit_in_word);
++ }
++
++ val &= dev->tnode_mask;
++ val <<= dev->chunk_grp_bits;
++
++ return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of top_level
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id)
++{
++ struct yaffs_tnode *tn = file_struct->top;
++ u32 i;
++ int required_depth;
++ int level = file_struct->top_level;
++
++ (void) dev;
++
++ /* Check sane level and chunk Id */
++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (i) {
++ i >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level)
++ return NULL; /* Not tall enough, so we can't find it */
++
++ /* Traverse down to level 0 */
++ while (level > 0 && tn) {
++ tn = tn->internal[(chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (level - 1) *
++ YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK];
++ level--;
++ }
++
++ return tn;
++}
++
++/* add_find_tnode_0 finds the level 0 tnode if it exists,
++ * otherwise first expands the tree.
++ * This happens in two steps:
++ * 1. If the tree isn't tall enough, then make it taller.
++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the
++ * specified tn will be plugged into the ttree.
++ */
++
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn)
++{
++ int required_depth;
++ int i;
++ int l;
++ struct yaffs_tnode *tn;
++ u32 x;
++
++ /* Check sane level and page Id */
++ if (file_struct->top_level < 0 ||
++ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level) {
++ /* Not tall enough, gotta make the tree taller */
++ for (i = file_struct->top_level; i < required_depth; i++) {
++
++ tn = yaffs_get_tnode(dev);
++
++ if (tn) {
++ tn->internal[0] = file_struct->top;
++ file_struct->top = tn;
++ file_struct->top_level++;
++ } else {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: no more tnodes");
++ return NULL;
++ }
++ }
++ }
++
++ /* Traverse down to level 0, adding anything we need */
++
++ l = file_struct->top_level;
++ tn = file_struct->top;
++
++ if (l > 0) {
++ while (l > 0 && tn) {
++ x = (chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK;
++
++ if ((l > 1) && !tn->internal[x]) {
++ /* Add missing non-level-zero tnode */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ } else if (l == 1) {
++ /* Looking from level 1 at level 0 */
++ if (passed_tn) {
++ /* If we already have one, release it */
++ if (tn->internal[x])
++ yaffs_free_tnode(dev,
++ tn->internal[x]);
++ tn->internal[x] = passed_tn;
++
++ } else if (!tn->internal[x]) {
++ /* Don't have one, none passed in */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ }
++ }
++
++ tn = tn->internal[x];
++ l--;
++ }
++ } else {
++ /* top is level 0 */
++ if (passed_tn) {
++ memcpy(tn, passed_tn,
++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
++ yaffs_free_tnode(dev, passed_tn);
++ }
++ }
++
++ return tn;
++}
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++ int chunk_obj)
++{
++ return (tags->chunk_id == chunk_obj &&
++ tags->obj_id == obj_id &&
++ !tags->is_deleted) ? 1 : 0;
++
++}
++
++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
++ struct yaffs_ext_tags *tags, int obj_id,
++ int inode_chunk)
++{
++ int j;
++
++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
++ if (yaffs_check_chunk_bit
++ (dev, the_chunk / dev->param.chunks_per_block,
++ the_chunk % dev->param.chunks_per_block)) {
++
++ if (dev->chunk_grp_size == 1)
++ return the_chunk;
++ else {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ tags);
++ if (yaffs_tags_match(tags,
++ obj_id, inode_chunk)) {
++ /* found it; */
++ return the_chunk;
++ }
++ }
++ }
++ the_chunk++;
++ }
++ return -1;
++}
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /*Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ int ret_val = -1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++ return ret_val;
++}
++
++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /* Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ struct yaffs_dev *dev = in->my_dev;
++ int ret_val = -1;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++
++ /* Delete the entry in the filestructure (if found) */
++ if (ret_val != -1)
++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
++
++ return ret_val;
++}
++
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan)
++{
++ /* NB in_scan is zero unless scanning.
++ * For forward scanning, in_scan is > 0;
++ * for backward scanning in_scan is < 0
++ *
++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
++ */
++
++ struct yaffs_tnode *tn;
++ struct yaffs_dev *dev = in->my_dev;
++ int existing_cunk;
++ struct yaffs_ext_tags existing_tags;
++ struct yaffs_ext_tags new_tags;
++ unsigned existing_serial, new_serial;
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
++ /* Just ignore an attempt at putting a chunk into a non-file
++ * during scanning.
++ * If it is not during Scanning then something went wrong!
++ */
++ if (!in_scan) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy:attempt to put data chunk into a non-file"
++ );
++ BUG();
++ }
++
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++
++ tn = yaffs_add_find_tnode_0(dev,
++ &in->variant.file_variant,
++ inode_chunk, NULL);
++ if (!tn)
++ return YAFFS_FAIL;
++
++ if (!nand_chunk)
++ /* Dummy insert, bail now */
++ return YAFFS_OK;
++
++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ if (in_scan != 0) {
++ /* If we're scanning then we need to test for duplicates
++ * NB This does not need to be efficient since it should only
++ * happen when the power fails during a write, then only one
++ * chunk should ever be affected.
++ *
++ * Correction for YAFFS2: This could happen quite a lot and we
++ * need to think about efficiency! TODO
++ * Update: For backward scanning we don't need to re-read tags
++ * so this is quite cheap.
++ */
++
++ if (existing_cunk > 0) {
++ /* NB Right now existing chunk will not be real
++ * chunk_id if the chunk group size > 1
++ * thus we have to do a FindChunkInFile to get the
++ * real chunk id.
++ *
++ * We have a duplicate now we need to decide which
++ * one to use:
++ *
++ * Backwards scanning YAFFS2: The old one is what
++ * we use, dump the new one.
++ * YAFFS1: Get both sets of tags and compare serial
++ * numbers.
++ */
++
++ if (in_scan > 0) {
++ /* Only do this for forward scanning */
++ yaffs_rd_chunk_tags_nand(dev,
++ nand_chunk,
++ NULL, &new_tags);
++
++ /* Do a proper find */
++ existing_cunk =
++ yaffs_find_chunk_in_file(in, inode_chunk,
++ &existing_tags);
++ }
++
++ if (existing_cunk <= 0) {
++ /*Hoosterman - how did this happen? */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: existing chunk < 0 in scan"
++ );
++
++ }
++
++ /* NB The deleted flags should be false, otherwise
++ * the chunks will not be loaded during a scan
++ */
++
++ if (in_scan > 0) {
++ new_serial = new_tags.serial_number;
++ existing_serial = existing_tags.serial_number;
++ }
++
++ if ((in_scan > 0) &&
++ (existing_cunk <= 0 ||
++ ((existing_serial + 1) & 3) == new_serial)) {
++ /* Forward scanning.
++ * Use new
++ * Delete the old one and drop through to
++ * update the tnode
++ */
++ yaffs_chunk_del(dev, existing_cunk, 1,
++ __LINE__);
++ } else {
++ /* Backward scanning or we want to use the
++ * existing one
++ * Delete the new one and return early so that
++ * the tnode isn't changed
++ */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++ }
++
++ }
++
++ if (existing_cunk == 0)
++ in->n_data_chunks++;
++
++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
++
++ return YAFFS_OK;
++}
++
++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
++{
++ struct yaffs_block_info *the_block;
++ unsigned block_no;
++
++ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
++
++ block_no = chunk / dev->param.chunks_per_block;
++ the_block = yaffs_get_block_info(dev, block_no);
++ if (the_block) {
++ the_block->soft_del_pages++;
++ dev->n_free_chunks++;
++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
++ }
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
++ * the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls
++ * the chunk out of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks
++ * are soft deleted.
++ */
++
++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
++ u32 level, int chunk_offset)
++{
++ int i;
++ int the_chunk;
++ int all_done = 1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = YAFFS_NTNODES_INTERNAL - 1;
++ all_done && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ all_done =
++ yaffs_soft_del_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ if (all_done) {
++ yaffs_free_tnode(dev,
++ tn->internal[i]);
++ tn->internal[i] = NULL;
++ } else {
++ /* Can this happen? */
++ }
++ }
++ }
++ return (all_done) ? 1 : 0;
++ }
++
++ /* level 0 */
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk) {
++ yaffs_soft_del_chunk(dev, the_chunk);
++ yaffs_load_tnode_0(dev, tn, i, 0);
++ }
++ }
++ return 1;
++}
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_obj *parent;
++
++ yaffs_verify_obj_in_dir(obj);
++ parent = obj->parent;
++
++ yaffs_verify_dir(parent);
++
++ if (dev && dev->param.remove_obj_fn)
++ dev->param.remove_obj_fn(obj);
++
++ list_del_init(&obj->siblings);
++ obj->parent = NULL;
++
++ yaffs_verify_dir(parent);
++}
++
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
++{
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a null pointer directory"
++ );
++ BUG();
++ return;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a non-directory"
++ );
++ BUG();
++ }
++
++ if (obj->siblings.prev == NULL) {
++ /* Not initialised */
++ BUG();
++ }
++
++ yaffs_verify_dir(directory);
++
++ yaffs_remove_obj_from_dir(obj);
++
++ /* Now add it */
++ list_add(&obj->siblings, &directory->variant.dir_variant.children);
++ obj->parent = directory;
++
++ if (directory == obj->my_dev->unlinked_dir
++ || directory == obj->my_dev->del_dir) {
++ obj->unlinked = 1;
++ obj->my_dev->n_unlinked_files++;
++ obj->rename_allowed = 0;
++ }
++
++ yaffs_verify_dir(directory);
++ yaffs_verify_obj_in_dir(obj);
++}
++
++static int yaffs_change_obj_name(struct yaffs_obj *obj,
++ struct yaffs_obj *new_dir,
++ const YCHAR *new_name, int force, int shadows)
++{
++ int unlink_op;
++ int del_op;
++ struct yaffs_obj *existing_target;
++
++ if (new_dir == NULL)
++ new_dir = obj->parent; /* use the old directory */
++
++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_change_obj_name: new_dir is not a directory"
++ );
++ BUG();
++ }
++
++ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
++ del_op = (new_dir == obj->my_dev->del_dir);
++
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++
++ /* If the object is a file going into the unlinked directory,
++ * then it is OK to just stuff it in since duplicate names are OK.
++ * else only proceed if the new name does not exist and we're putting
++ * it into a directory.
++ */
++ if (!(unlink_op || del_op || force ||
++ shadows > 0 || !existing_target) ||
++ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ return YAFFS_FAIL;
++
++ yaffs_set_obj_name(obj, new_name);
++ obj->dirty = 1;
++ yaffs_add_obj_to_dir(new_dir, obj);
++
++ if (unlink_op)
++ obj->unlinked = 1;
++
++ /* If it is a deletion then we mark it as a shrink for gc */
++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++/*------------------------ Short Operations Cache ------------------------------
++ * In many situations where there is no high level buffering a lot of
++ * reads might be short sequential reads, and a lot of writes may be short
++ * sequential writes. eg. scanning/writing a jpeg file.
++ * In these cases, a short read/write cache can provide a huge perfomance
++ * benefit with dumb-as-a-rock code.
++ * In Linux, the page cache provides read buffering and the short op cache
++ * provides write buffering.
++ *
++ * There are a small number (~10) of cache chunks per device so that we don't
++ * need a very intelligent search.
++ */
++
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++ struct yaffs_cache *cache;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ for (i = 0; i < n_caches; i++) {
++ cache = &dev->cache[i];
++ if (cache->object == obj && cache->dirty)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void yaffs_flush_file_cache(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int lowest = -99; /* Stop compiler whining. */
++ int i;
++ struct yaffs_cache *cache;
++ int chunk_written = 0;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ if (n_caches < 1)
++ return;
++ do {
++ cache = NULL;
++
++ /* Find the lowest dirty chunk for this object */
++ for (i = 0; i < n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].dirty) {
++ if (!cache ||
++ dev->cache[i].chunk_id < lowest) {
++ cache = &dev->cache[i];
++ lowest = cache->chunk_id;
++ }
++ }
++ }
++
++ if (cache && !cache->locked) {
++ /* Write it out and free it up */
++ chunk_written =
++ yaffs_wr_data_obj(cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ cache->object = NULL;
++ }
++ } while (cache && chunk_written > 0);
++
++ if (cache)
++ /* Hoosterman, disk full while writing cache out. */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no space during cache write");
++}
++
++/*yaffs_flush_whole_cache(dev)
++ *
++ *
++ */
++
++void yaffs_flush_whole_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int n_caches = dev->param.n_caches;
++ int i;
++
++ /* Find a dirty object in the cache and flush it...
++ * until there are no further dirty objects.
++ */
++ do {
++ obj = NULL;
++ for (i = 0; i < n_caches && !obj; i++) {
++ if (dev->cache[i].object && dev->cache[i].dirty)
++ obj = dev->cache[i].object;
++ }
++ if (obj)
++ yaffs_flush_file_cache(obj);
++ } while (obj);
++
++}
++
++/* Grab us a cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->param.n_caches > 0) {
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (!dev->cache[i].object)
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_cache *cache;
++ struct yaffs_obj *the_obj;
++ int usage;
++ int i;
++ int pushout;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ /* Try find a non-dirty one... */
++
++ cache = yaffs_grab_chunk_worker(dev);
++
++ if (!cache) {
++ /* They were all dirty, find the LRU object and flush
++ * its cache, then find again.
++ * NB what's here is not very accurate,
++ * we actually flush the object with the LRU chunk.
++ */
++
++ /* With locking we can't assume we can use entry zero,
++ * Set the_obj to a valid pointer for Coverity. */
++ the_obj = dev->cache[0].object;
++ usage = -1;
++ cache = NULL;
++ pushout = -1;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object &&
++ !dev->cache[i].locked &&
++ (dev->cache[i].last_use < usage ||
++ !cache)) {
++ usage = dev->cache[i].last_use;
++ the_obj = dev->cache[i].object;
++ cache = &dev->cache[i];
++ pushout = i;
++ }
++ }
++
++ if (!cache || cache->dirty) {
++ /* Flush and try again */
++ yaffs_flush_file_cache(the_obj);
++ cache = yaffs_grab_chunk_worker(dev);
++ }
++ }
++ return cache;
++}
++
++/* Find a cached chunk */
++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
++ int chunk_id)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].chunk_id == chunk_id) {
++ dev->cache_hits++;
++
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
++ int is_write)
++{
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return;
++
++ if (dev->cache_last_use < 0 ||
++ dev->cache_last_use > 100000000) {
++ /* Reset the cache usages */
++ for (i = 1; i < dev->param.n_caches; i++)
++ dev->cache[i].last_use = 0;
++
++ dev->cache_last_use = 0;
++ }
++ dev->cache_last_use++;
++ cache->last_use = dev->cache_last_use;
++
++ if (is_write)
++ cache->dirty = 1;
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
++{
++ struct yaffs_cache *cache;
++
++ if (object->my_dev->param.n_caches > 0) {
++ cache = yaffs_find_chunk_cache(object, chunk_id);
++
++ if (cache)
++ cache->object = NULL;
++ }
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.n_caches > 0) {
++ /* Invalidate it. */
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == in)
++ dev->cache[i].object = NULL;
++ }
++ }
++}
++
++static void yaffs_unhash_obj(struct yaffs_obj *obj)
++{
++ int bucket;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ /* If it is still linked into the bucket list, free from the list */
++ if (!list_empty(&obj->hash_link)) {
++ list_del_init(&obj->hash_link);
++ bucket = yaffs_hash_fn(obj->obj_id);
++ dev->obj_bucket[bucket].count--;
++ }
++}
++
++/* FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_free_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj) {
++ BUG();
++ return;
++ }
++ dev = obj->my_dev;
++ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
++ obj, obj->my_inode);
++ if (obj->parent)
++ BUG();
++ if (!list_empty(&obj->siblings))
++ BUG();
++
++ if (obj->my_inode) {
++ /* We're still hooked up to a cached inode.
++ * Don't delete now, but mark for later deletion
++ */
++ obj->defered_free = 1;
++ return;
++ }
++
++ yaffs_unhash_obj(obj);
++
++ yaffs_free_raw_obj(dev, obj);
++ dev->n_obj--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj)
++{
++ if (obj->defered_free)
++ yaffs_free_obj(obj);
++}
++
++static int yaffs_generic_obj_del(struct yaffs_obj *in)
++{
++ /* Iinvalidate the file's data in the cache, without flushing. */
++ yaffs_invalidate_whole_cache(in);
++
++ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
++ /* Move to unlinked directory so we have a deletion record */
++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
++ 0);
++ }
++
++ yaffs_remove_obj_from_dir(in);
++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
++ in->hdr_chunk = 0;
++
++ yaffs_free_obj(in);
++ return YAFFS_OK;
++
++}
++
++static void yaffs_soft_del_file(struct yaffs_obj *obj)
++{
++ if (!obj->deleted ||
++ obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
++ obj->soft_del)
++ return;
++
++ if (obj->n_data_chunks <= 0) {
++ /* Empty file with no duplicate object headers,
++ * just delete it immediately */
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: Deleting empty file %d",
++ obj->obj_id);
++ yaffs_generic_obj_del(obj);
++ } else {
++ yaffs_soft_del_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.
++ file_variant.top_level, 0);
++ obj->soft_del = 1;
++ }
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
++ struct yaffs_tnode *tn, u32 level,
++ int del0)
++{
++ int i;
++ int has_data;
++
++ if (!tn)
++ return tn;
++
++ has_data = 0;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i]) {
++ tn->internal[i] =
++ yaffs_prune_worker(dev,
++ tn->internal[i],
++ level - 1,
++ (i == 0) ? del0 : 1);
++ }
++
++ if (tn->internal[i])
++ has_data++;
++ }
++ } else {
++ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
++ u32 *map = (u32 *) tn;
++
++ for (i = 0; !has_data && i < tnode_size_u32; i++) {
++ if (map[i])
++ has_data++;
++ }
++ }
++
++ if (has_data == 0 && del0) {
++ /* Free and return NULL */
++ yaffs_free_tnode(dev, tn);
++ tn = NULL;
++ }
++ return tn;
++}
++
++static int yaffs_prune_tree(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct)
++{
++ int i;
++ int has_data;
++ int done = 0;
++ struct yaffs_tnode *tn;
++
++ if (file_struct->top_level < 1)
++ return YAFFS_OK;
++
++ file_struct->top =
++ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
++
++ /* Now we have a tree with all the non-zero branches NULL but
++ * the height is the same as it was.
++ * Let's see if we can trim internal tnodes to shorten the tree.
++ * We can do this if only the 0th element in the tnode is in use
++ * (ie all the non-zero are NULL)
++ */
++
++ while (file_struct->top_level && !done) {
++ tn = file_struct->top;
++
++ has_data = 0;
++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i])
++ has_data++;
++ }
++
++ if (!has_data) {
++ file_struct->top = tn->internal[0];
++ file_struct->top_level--;
++ yaffs_free_tnode(dev, tn);
++ } else {
++ done = 1;
++ }
++ }
++
++ return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* alloc_empty_obj gets us a clean Object.*/
++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
++
++ if (!obj)
++ return obj;
++
++ dev->n_obj++;
++
++ /* Now sweeten it up... */
++
++ memset(obj, 0, sizeof(struct yaffs_obj));
++ obj->being_created = 1;
++
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0;
++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
++ INIT_LIST_HEAD(&(obj->hard_links));
++ INIT_LIST_HEAD(&(obj->hash_link));
++ INIT_LIST_HEAD(&obj->siblings);
++
++ /* Now make the directory sane */
++ if (dev->root_dir) {
++ obj->parent = dev->root_dir;
++ list_add(&(obj->siblings),
++ &dev->root_dir->variant.dir_variant.children);
++ }
++
++ /* Add it to the lost and found directory.
++ * NB Can't put root or lost-n-found in lost-n-found so
++ * check if lost-n-found exists first
++ */
++ if (dev->lost_n_found)
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++
++ obj->being_created = 0;
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return obj;
++}
++
++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
++{
++ int i;
++ int l = 999;
++ int lowest = 999999;
++
++ /* Search for the shortest list or one that
++ * isn't too long.
++ */
++
++ for (i = 0; i < 10 && lowest > 4; i++) {
++ dev->bucket_finder++;
++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
++ lowest = dev->obj_bucket[dev->bucket_finder].count;
++ l = dev->bucket_finder;
++ }
++ }
++
++ return l;
++}
++
++static int yaffs_new_obj_id(struct yaffs_dev *dev)
++{
++ int bucket = yaffs_find_nice_bucket(dev);
++ int found = 0;
++ struct list_head *i;
++ u32 n = (u32) bucket;
++
++ /* Now find an object value that has not already been taken
++ * by scanning the list.
++ */
++
++ while (!found) {
++ found = 1;
++ n += YAFFS_NOBJECT_BUCKETS;
++ if (1 || dev->obj_bucket[bucket].count > 0) {
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* If there is already one in the list */
++ if (i && list_entry(i, struct yaffs_obj,
++ hash_link)->obj_id == n) {
++ found = 0;
++ }
++ }
++ }
++ }
++ return n;
++}
++
++static void yaffs_hash_obj(struct yaffs_obj *in)
++{
++ int bucket = yaffs_hash_fn(in->obj_id);
++ struct yaffs_dev *dev = in->my_dev;
++
++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
++ dev->obj_bucket[bucket].count++;
++}
++
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
++{
++ int bucket = yaffs_hash_fn(number);
++ struct list_head *i;
++ struct yaffs_obj *in;
++
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* Look if it is in the list */
++ in = list_entry(i, struct yaffs_obj, hash_link);
++ if (in->obj_id == number) {
++ /* Don't show if it is defered free */
++ if (in->defered_free)
++ return NULL;
++ return in;
++ }
++ }
++
++ return NULL;
++}
++
++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++ struct yaffs_tnode *tn = NULL;
++
++ if (number < 0)
++ number = yaffs_new_obj_id(dev);
++
++ if (type == YAFFS_OBJECT_TYPE_FILE) {
++ tn = yaffs_get_tnode(dev);
++ if (!tn)
++ return NULL;
++ }
++
++ the_obj = yaffs_alloc_empty_obj(dev);
++ if (!the_obj) {
++ if (tn)
++ yaffs_free_tnode(dev, tn);
++ return NULL;
++ }
++
++ the_obj->fake = 0;
++ the_obj->rename_allowed = 1;
++ the_obj->unlink_allowed = 1;
++ the_obj->obj_id = number;
++ yaffs_hash_obj(the_obj);
++ the_obj->variant_type = type;
++ yaffs_load_current_time(the_obj, 1, 1);
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ the_obj->variant.file_variant.file_size = 0;
++ the_obj->variant.file_variant.scanned_size = 0;
++ the_obj->variant.file_variant.shrink_size =
++ yaffs_max_file_size(dev);
++ the_obj->variant.file_variant.top_level = 0;
++ the_obj->variant.file_variant.top = tn;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* No action required */
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* todo this should not happen */
++ break;
++ }
++ return the_obj;
++}
++
++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
++ int number, u32 mode)
++{
++
++ struct yaffs_obj *obj =
++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++
++ if (!obj)
++ return NULL;
++
++ obj->fake = 1; /* it is fake so it might not use NAND */
++ obj->rename_allowed = 0;
++ obj->unlink_allowed = 0;
++ obj->deleted = 0;
++ obj->unlinked = 0;
++ obj->yst_mode = mode;
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0; /* Not a valid chunk. */
++ return obj;
++
++}
++
++
++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ int i;
++
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++ yaffs_init_raw_tnodes_and_objs(dev);
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
++ dev->obj_bucket[i].count = 0;
++ }
++}
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++
++ if (number > 0)
++ the_obj = yaffs_find_by_number(dev, number);
++
++ if (!the_obj)
++ the_obj = yaffs_new_obj(dev, number, type);
++
++ return the_obj;
++
++}
++
++YCHAR *yaffs_clone_str(const YCHAR *str)
++{
++ YCHAR *new_str = NULL;
++ int len;
++
++ if (!str)
++ str = _Y("");
++
++ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
++ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
++ if (new_str) {
++ strncpy(new_str, str, len);
++ new_str[len] = 0;
++ }
++ return new_str;
++
++}
++/*
++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ * create dir/a : update dir's mtime/ctime
++ * rm dir/a: update dir's mtime/ctime
++ * modify dir/a: don't update dir's mtimme/ctime
++ *
++ * This can be handled immediately or defered. Defering helps reduce the number
++ * of updates when many files in a directory are changed within a brief period.
++ *
++ * If the directory updating is defered then yaffs_update_dirty_dirs must be
++ * called periodically.
++ */
++
++static void yaffs_update_parent(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj)
++ return;
++ dev = obj->my_dev;
++ obj->dirty = 1;
++ yaffs_load_current_time(obj, 0, 1);
++ if (dev->param.defered_dir_update) {
++ struct list_head *link = &obj->variant.dir_variant.dirty;
++
++ if (list_empty(link)) {
++ list_add(link, &dev->dirty_dirs);
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Added object %d to dirty directories",
++ obj->obj_id);
++ }
++
++ } else {
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
++{
++ struct list_head *link;
++ struct yaffs_obj *obj;
++ struct yaffs_dir_var *d_s;
++ union yaffs_obj_var *o_v;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
++
++ while (!list_empty(&dev->dirty_dirs)) {
++ link = dev->dirty_dirs.next;
++ list_del_init(link);
++
++ d_s = list_entry(link, struct yaffs_dir_var, dirty);
++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
++ obj = list_entry(o_v, struct yaffs_obj, variant);
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
++ obj->obj_id);
++
++ if (obj->dirty)
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++/*
++ * Mknod (create) a new object.
++ * equiv_obj only has meaning for a hard link;
++ * alias_str only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
++ struct yaffs_obj *parent,
++ const YCHAR *name,
++ u32 mode,
++ u32 uid,
++ u32 gid,
++ struct yaffs_obj *equiv_obj,
++ const YCHAR *alias_str, u32 rdev)
++{
++ struct yaffs_obj *in;
++ YCHAR *str = NULL;
++ struct yaffs_dev *dev = parent->my_dev;
++
++ /* Check if the entry exists.
++ * If it does then fail the call since we don't want a dup. */
++ if (yaffs_find_by_name(parent, name))
++ return NULL;
++
++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ str = yaffs_clone_str(alias_str);
++ if (!str)
++ return NULL;
++ }
++
++ in = yaffs_new_obj(dev, -1, type);
++
++ if (!in) {
++ kfree(str);
++ return NULL;
++ }
++
++ in->hdr_chunk = 0;
++ in->valid = 1;
++ in->variant_type = type;
++
++ in->yst_mode = mode;
++
++ yaffs_attribs_init(in, gid, uid, rdev);
++
++ in->n_data_chunks = 0;
++
++ yaffs_set_obj_name(in, name);
++ in->dirty = 1;
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ in->my_dev = parent->my_dev;
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.alias = str;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardlink_variant.equiv_obj = equiv_obj;
++ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
++ list_add(&in->hard_links, &equiv_obj->hard_links);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* do nothing */
++ break;
++ }
++
++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
++ /* Could not create the object header, fail */
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ if (in)
++ yaffs_update_parent(parent);
++
++ return in;
++}
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++ uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++ mode, uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++ uid, gid, NULL, NULL, rdev);
++}
++
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++ uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_link_obj returns the object id of the equivalent object.*/
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++ struct yaffs_obj *equiv_obj)
++{
++ /* Get the real object in case we were fed a hard link obj */
++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
++
++ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
++ parent, name, 0, 0, 0,
++ equiv_obj, NULL, 0))
++ return equiv_obj;
++
++ return NULL;
++
++}
++
++
++
++/*---------------------- Block Management and Page Allocation -------------*/
++
++static void yaffs_deinit_blocks(struct yaffs_dev *dev)
++{
++ if (dev->block_info_alt && dev->block_info)
++ vfree(dev->block_info);
++ else
++ kfree(dev->block_info);
++
++ dev->block_info_alt = 0;
++
++ dev->block_info = NULL;
++
++ if (dev->chunk_bits_alt && dev->chunk_bits)
++ vfree(dev->chunk_bits);
++ else
++ kfree(dev->chunk_bits);
++ dev->chunk_bits_alt = 0;
++ dev->chunk_bits = NULL;
++}
++
++static int yaffs_init_blocks(struct yaffs_dev *dev)
++{
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ dev->block_info = NULL;
++ dev->chunk_bits = NULL;
++ dev->alloc_block = -1; /* force it to get a new one */
++
++ /* If the first allocation strategy fails, thry the alternate one */
++ dev->block_info =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
++ if (!dev->block_info) {
++ dev->block_info =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_info));
++ dev->block_info_alt = 1;
++ } else {
++ dev->block_info_alt = 0;
++ }
++
++ if (!dev->block_info)
++ goto alloc_error;
++
++ /* Set up dynamic blockinfo stuff. Round up bytes. */
++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
++ dev->chunk_bits =
++ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
++ if (!dev->chunk_bits) {
++ dev->chunk_bits =
++ vmalloc(dev->chunk_bit_stride * n_blocks);
++ dev->chunk_bits_alt = 1;
++ } else {
++ dev->chunk_bits_alt = 0;
++ }
++ if (!dev->chunk_bits)
++ goto alloc_error;
++
++
++ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
++ return YAFFS_OK;
++
++alloc_error:
++ yaffs_deinit_blocks(dev);
++ return YAFFS_FAIL;
++}
++
++
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
++ int erased_ok = 0;
++ int i;
++
++ /* If the block is still healthy erase it and mark as clean.
++ * If the block has had a data failure, then retire it.
++ */
++
++ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++ "yaffs_block_became_dirty block %d state %d %s",
++ block_no, bi->block_state,
++ (bi->needs_retiring) ? "needs retiring" : "");
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
++
++ /* If this is the block being garbage collected then stop gc'ing */
++ if (block_no == dev->gc_block)
++ dev->gc_block = 0;
++
++ /* If this block is currently the best candidate for gc
++ * then drop as a candidate */
++ if (block_no == dev->gc_dirtiest) {
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ }
++
++ if (!bi->needs_retiring) {
++ yaffs2_checkpt_invalidate(dev);
++ erased_ok = yaffs_erase_block(dev, block_no);
++ if (!erased_ok) {
++ dev->n_erase_failures++;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Erasure failed %d", block_no);
++ }
++ }
++
++ /* Verify erasure if needed */
++ if (erased_ok &&
++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
++ !yaffs_skip_verification(dev))) {
++ for (i = 0; i < dev->param.chunks_per_block; i++) {
++ if (!yaffs_check_chunk_erased(dev,
++ block_no * dev->param.chunks_per_block + i)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ ">>Block %d erasure supposedly OK, but chunk %d not erased",
++ block_no, i);
++ }
++ }
++ }
++
++ if (!erased_ok) {
++ /* We lost a block of free space */
++ dev->n_free_chunks -= dev->param.chunks_per_block;
++ yaffs_retire_block(dev, block_no);
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d retired", block_no);
++ return;
++ }
++
++ /* Clean it up... */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ bi->seq_number = 0;
++ dev->n_erased_blocks++;
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++ bi->has_shrink_hdr = 0;
++ bi->skip_erased_check = 1; /* Clean, so no need to check */
++ bi->gc_prioritise = 0;
++ bi->has_summary = 0;
++
++ yaffs_clear_chunk_bits(dev, block_no);
++
++ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
++}
++
++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int old_chunk, u8 *buffer)
++{
++ int new_chunk;
++ int mark_flash = 1;
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj *object;
++ int matching_chunk;
++ int ret_val = YAFFS_OK;
++
++ memset(&tags, 0, sizeof(tags));
++ yaffs_rd_chunk_tags_nand(dev, old_chunk,
++ buffer, &tags);
++ object = yaffs_find_by_number(dev, tags.obj_id);
++
++ yaffs_trace(YAFFS_TRACE_GC_DETAIL,
++ "Collecting chunk in block %d, %d %d %d ",
++ dev->gc_chunk, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++
++ if (object && !yaffs_skip_verification(dev)) {
++ if (tags.chunk_id == 0)
++ matching_chunk =
++ object->hdr_chunk;
++ else if (object->soft_del)
++ /* Defeat the test */
++ matching_chunk = old_chunk;
++ else
++ matching_chunk =
++ yaffs_find_chunk_in_file
++ (object, tags.chunk_id,
++ NULL);
++
++ if (old_chunk != matching_chunk)
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "gc: page in gc mismatch: %d %d %d %d",
++ old_chunk,
++ matching_chunk,
++ tags.obj_id,
++ tags.chunk_id);
++ }
++
++ if (!object) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "page %d in gc has no object: %d %d %d ",
++ old_chunk,
++ tags.obj_id, tags.chunk_id,
++ tags.n_bytes);
++ }
++
++ if (object &&
++ object->deleted &&
++ object->soft_del && tags.chunk_id != 0) {
++ /* Data chunk in a soft deleted file,
++ * throw it away.
++ * It's a soft deleted data chunk,
++ * No need to copy this, just forget
++ * about it and fix up the object.
++ */
++
++ /* Free chunks already includes
++ * softdeleted chunks, how ever this
++ * chunk is going to soon be really
++ * deleted which will increment free
++ * chunks. We have to decrement free
++ * chunks so this works out properly.
++ */
++ dev->n_free_chunks--;
++ bi->soft_del_pages--;
++
++ object->n_data_chunks--;
++ if (object->n_data_chunks <= 0) {
++ /* remeber to clean up obj */
++ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
++ dev->n_clean_ups++;
++ }
++ mark_flash = 0;
++ } else if (object) {
++ /* It's either a data chunk in a live
++ * file or an ObjectHeader, so we're
++ * interested in it.
++ * NB Need to keep the ObjectHeaders of
++ * deleted files until the whole file
++ * has been deleted off
++ */
++ tags.serial_number++;
++ dev->n_gc_copies++;
++
++ if (tags.chunk_id == 0) {
++ /* It is an object Id,
++ * We need to nuke the
++ * shrinkheader flags since its
++ * work is done.
++ * Also need to clean up
++ * shadowing.
++ */
++ struct yaffs_obj_hdr *oh;
++ oh = (struct yaffs_obj_hdr *) buffer;
++
++ oh->is_shrink = 0;
++ tags.extra_is_shrink = 0;
++ oh->shadows_obj = 0;
++ oh->inband_shadowed_obj_id = 0;
++ tags.extra_shadows = 0;
++
++ /* Update file size */
++ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++ yaffs_oh_size_load(oh,
++ object->variant.file_variant.file_size);
++ tags.extra_file_size =
++ object->variant.file_variant.file_size;
++ }
++
++ yaffs_verify_oh(object, oh, &tags, 1);
++ new_chunk =
++ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
++ } else {
++ new_chunk =
++ yaffs_write_new_chunk(dev, buffer, &tags, 1);
++ }
++
++ if (new_chunk < 0) {
++ ret_val = YAFFS_FAIL;
++ } else {
++
++ /* Now fix up the Tnodes etc. */
++
++ if (tags.chunk_id == 0) {
++ /* It's a header */
++ object->hdr_chunk = new_chunk;
++ object->serial = tags.serial_number;
++ } else {
++ /* It's a data chunk */
++ yaffs_put_chunk_in_file(object, tags.chunk_id,
++ new_chunk, 0);
++ }
++ }
++ }
++ if (ret_val == YAFFS_OK)
++ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
++ return ret_val;
++}
++
++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
++{
++ int old_chunk;
++ int ret_val = YAFFS_OK;
++ int i;
++ int is_checkpt_block;
++ int max_copies;
++ int chunks_before = yaffs_get_erased_chunks(dev);
++ int chunks_after;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
++
++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d, in use %d, shrink %d, whole_block %d",
++ block, bi->pages_in_use, bi->has_shrink_hdr,
++ whole_block);
++
++ /*yaffs_verify_free_chunks(dev); */
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
++
++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
++
++ dev->gc_disable = 1;
++
++ yaffs_summary_gc(dev, block);
++
++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d that has no chunks in use",
++ block);
++ yaffs_block_became_dirty(dev, block);
++ } else {
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_verify_blk(dev, bi, block);
++
++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
++
++ for (/* init already done */ ;
++ ret_val == YAFFS_OK &&
++ dev->gc_chunk < dev->param.chunks_per_block &&
++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
++ max_copies > 0;
++ dev->gc_chunk++, old_chunk++) {
++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
++ /* Page is in use and might need to be copied */
++ max_copies--;
++ ret_val = yaffs_gc_process_chunk(dev, bi,
++ old_chunk, buffer);
++ }
++ }
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ yaffs_verify_collected_blk(dev, bi, block);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ /*
++ * The gc did not complete. Set block state back to FULL
++ * because checkpointing does not restore gc.
++ */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ } else {
++ /* The gc completed. */
++ /* Do any required cleanups */
++ for (i = 0; i < dev->n_clean_ups; i++) {
++ /* Time to delete the file too */
++ struct yaffs_obj *object =
++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
++ if (object) {
++ yaffs_free_tnode(dev,
++ object->variant.file_variant.top);
++ object->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: About to finally delete object %d",
++ object->obj_id);
++ yaffs_generic_obj_del(object);
++ object->my_dev->n_deleted_files--;
++ }
++
++ }
++ chunks_after = yaffs_get_erased_chunks(dev);
++ if (chunks_before >= chunks_after)
++ yaffs_trace(YAFFS_TRACE_GC,
++ "gc did not increase free chunks before %d after %d",
++ chunks_before, chunks_after);
++ dev->gc_block = 0;
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ dev->gc_disable = 0;
++
++ return ret_val;
++}
++
++/*
++ * find_gc_block() selects the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
++ int aggressive, int background)
++{
++ int i;
++ int iterations;
++ unsigned selected = 0;
++ int prioritised = 0;
++ int prioritised_exist = 0;
++ struct yaffs_block_info *bi;
++ int threshold;
++
++ /* First let's see if we need to grab a prioritised block */
++ if (dev->has_pending_prioritised_gc && !aggressive) {
++ dev->gc_dirtiest = 0;
++ bi = dev->block_info;
++ for (i = dev->internal_start_block;
++ i <= dev->internal_end_block && !selected; i++) {
++
++ if (bi->gc_prioritise) {
++ prioritised_exist = 1;
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ selected = i;
++ prioritised = 1;
++ }
++ }
++ bi++;
++ }
++
++ /*
++ * If there is a prioritised block and none was selected then
++ * this happened because there is at least one old dirty block
++ * gumming up the works. Let's gc the oldest dirty block.
++ */
++
++ if (prioritised_exist &&
++ !selected && dev->oldest_dirty_block > 0)
++ selected = dev->oldest_dirty_block;
++
++ if (!prioritised_exist) /* None found, so we can clear this */
++ dev->has_pending_prioritised_gc = 0;
++ }
++
++ /* If we're doing aggressive GC then we are happy to take a less-dirty
++ * block, and search harder.
++ * else (leasurely gc), then we only bother to do this if the
++ * block has only a few pages in use.
++ */
++
++ if (!selected) {
++ int pages_used;
++ int n_blocks =
++ dev->internal_end_block - dev->internal_start_block + 1;
++ if (aggressive) {
++ threshold = dev->param.chunks_per_block;
++ iterations = n_blocks;
++ } else {
++ int max_threshold;
++
++ if (background)
++ max_threshold = dev->param.chunks_per_block / 2;
++ else
++ max_threshold = dev->param.chunks_per_block / 8;
++
++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++
++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++ if (threshold > max_threshold)
++ threshold = max_threshold;
++
++ iterations = n_blocks / 16 + 1;
++ if (iterations > 100)
++ iterations = 100;
++ }
++
++ for (i = 0;
++ i < iterations &&
++ (dev->gc_dirtiest < 1 ||
++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
++ i++) {
++ dev->gc_block_finder++;
++ if (dev->gc_block_finder < dev->internal_start_block ||
++ dev->gc_block_finder > dev->internal_end_block)
++ dev->gc_block_finder =
++ dev->internal_start_block;
++
++ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
++
++ pages_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ pages_used < dev->param.chunks_per_block &&
++ (dev->gc_dirtiest < 1 ||
++ pages_used < dev->gc_pages_in_use) &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ dev->gc_dirtiest = dev->gc_block_finder;
++ dev->gc_pages_in_use = pages_used;
++ }
++ }
++
++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
++ selected = dev->gc_dirtiest;
++ }
++
++ /*
++ * If nothing has been selected for a while, try the oldest dirty
++ * because that's gumming up the works.
++ */
++
++ if (!selected && dev->param.is_yaffs2 &&
++ dev->gc_not_done >= (background ? 10 : 20)) {
++ yaffs2_find_oldest_dirty_seq(dev);
++ if (dev->oldest_dirty_block > 0) {
++ selected = dev->oldest_dirty_block;
++ dev->gc_dirtiest = selected;
++ dev->oldest_dirty_gc_count++;
++ bi = yaffs_get_block_info(dev, selected);
++ dev->gc_pages_in_use =
++ bi->pages_in_use - bi->soft_del_pages;
++ } else {
++ dev->gc_not_done = 0;
++ }
++ }
++
++ if (selected) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC Selected block %d with %d free, prioritised:%d",
++ selected,
++ dev->param.chunks_per_block - dev->gc_pages_in_use,
++ prioritised);
++
++ dev->n_gc_blocks++;
++ if (background)
++ dev->bg_gcs++;
++
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ dev->gc_not_done = 0;
++ if (dev->refresh_skip > 0)
++ dev->refresh_skip--;
++ } else {
++ dev->gc_not_done++;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
++ dev->gc_block_finder, dev->gc_not_done, threshold,
++ dev->gc_dirtiest, dev->gc_pages_in_use,
++ dev->oldest_dirty_block, background ? " bg" : "");
++ }
++
++ return selected;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_check_gc(struct yaffs_dev *dev, int background)
++{
++ int aggressive = 0;
++ int gc_ok = YAFFS_OK;
++ int max_tries = 0;
++ int min_erased;
++ int erased_chunks;
++ int checkpt_block_adjust;
++
++ if (dev->param.gc_control_fn &&
++ (dev->param.gc_control_fn(dev) & 1) == 0)
++ return YAFFS_OK;
++
++ if (dev->gc_disable)
++ /* Bail out so we don't get recursive gc */
++ return YAFFS_OK;
++
++ /* This loop should pass the first time.
++ * Only loops here if the collection does not increase space.
++ */
++
++ do {
++ max_tries++;
++
++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
++
++ min_erased =
++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
++ erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ /* If we need a block soon then do aggressive gc. */
++ if (dev->n_erased_blocks < min_erased)
++ aggressive = 1;
++ else {
++ if (!background
++ && erased_chunks > (dev->n_free_chunks / 4))
++ break;
++
++ if (dev->gc_skip > 20)
++ dev->gc_skip = 20;
++ if (erased_chunks < dev->n_free_chunks / 2 ||
++ dev->gc_skip < 1 || background)
++ aggressive = 0;
++ else {
++ dev->gc_skip--;
++ break;
++ }
++ }
++
++ dev->gc_skip = 5;
++
++ /* If we don't already have a block being gc'd then see if we
++ * should start another */
++
++ if (dev->gc_block < 1 && !aggressive) {
++ dev->gc_block = yaffs2_find_refresh_block(dev);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++ if (dev->gc_block < 1) {
++ dev->gc_block =
++ yaffs_find_gc_block(dev, aggressive, background);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ if (dev->gc_block > 0) {
++ dev->all_gcs++;
++ if (!aggressive)
++ dev->passive_gc_count++;
++
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC n_erased_blocks %d aggressive %d",
++ dev->n_erased_blocks, aggressive);
++
++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
++ }
++
++ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
++ dev->gc_block > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
++ dev->n_erased_blocks, max_tries,
++ dev->gc_block);
++ }
++ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
++ (dev->gc_block > 0) && (max_tries < 2));
++
++ return aggressive ? gc_ok : YAFFS_OK;
++}
++
++/*
++ * yaffs_bg_gc()
++ * Garbage collects. Intended to be called from a background thread.
++ * Returns non-zero if at least half the free chunks are erased.
++ */
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
++{
++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
++
++ yaffs_check_gc(dev, 1);
++ return erased_chunks > dev->n_free_chunks / 2;
++}
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
++{
++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
++
++ if (nand_chunk >= 0)
++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
++ buffer, NULL);
++ else {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not found zero instead",
++ nand_chunk);
++ /* get sane (zero) data if you read a hole */
++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
++ return 0;
++ }
++
++}
++
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn)
++{
++ int block;
++ int page;
++ struct yaffs_ext_tags tags;
++ struct yaffs_block_info *bi;
++
++ if (chunk_id <= 0)
++ return;
++
++ dev->n_deletions++;
++ block = chunk_id / dev->param.chunks_per_block;
++ page = chunk_id % dev->param.chunks_per_block;
++
++ if (!yaffs_check_chunk_bit(dev, block, page))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Deleting invalid chunk %d", chunk_id);
++
++ bi = yaffs_get_block_info(dev, block);
++
++ yaffs2_update_oldest_dirty_seq(dev, block, bi);
++
++ yaffs_trace(YAFFS_TRACE_DELETION,
++ "line %d delete of chunk %d",
++ lyn, chunk_id);
++
++ if (!dev->param.is_yaffs2 && mark_flash &&
++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
++
++ memset(&tags, 0, sizeof(tags));
++ tags.is_deleted = 1;
++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
++ yaffs_handle_chunk_update(dev, chunk_id, &tags);
++ } else {
++ dev->n_unmarked_deletions++;
++ }
++
++ /* Pull out of the management area.
++ * If the whole block became dirty, this will kick off an erasure.
++ */
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
++ bi->block_state == YAFFS_BLOCK_STATE_FULL ||
++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->n_free_chunks++;
++ yaffs_clear_chunk_bit(dev, block, page);
++ bi->pages_in_use--;
++
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ yaffs_block_became_dirty(dev, block);
++ }
++ }
++}
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve)
++{
++ /* Find old chunk Need to do this to get serial number
++ * Write new one and patch into tree.
++ * Invalidate old tags.
++ */
++
++ int prev_chunk_id;
++ struct yaffs_ext_tags prev_tags;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_dev *dev = in->my_dev;
++
++ yaffs_check_gc(dev, 0);
++
++ /* Get the previous chunk at this location in the file if it exists.
++ * If it does not exist then put a zero into the tree. This creates
++ * the tnode now, rather than later when it is harder to clean up.
++ */
++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
++ if (prev_chunk_id < 1 &&
++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
++ return 0;
++
++ /* Set up new tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++
++ new_tags.chunk_id = inode_chunk;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number =
++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
++ new_tags.n_bytes = n_bytes;
++
++ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Writing %d bytes to chunk!!!!!!!!!",
++ n_bytes);
++ BUG();
++ }
++
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
++
++ if (new_chunk_id > 0) {
++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ yaffs_verify_file_sane(in);
++ }
++ return new_chunk_id;
++
++}
++
++
++
++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
++ const YCHAR *name, const void *value, int size,
++ int flags)
++{
++ struct yaffs_xattr_mod xmod;
++ int result;
++
++ xmod.set = set;
++ xmod.name = name;
++ xmod.data = value;
++ xmod.size = size;
++ xmod.flags = flags;
++ xmod.result = -ENOSPC;
++
++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
++
++ if (result > 0)
++ return xmod.result;
++ else
++ return -ENOSPC;
++}
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++ struct yaffs_xattr_mod *xmod)
++{
++ int retval = 0;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer = buffer + x_offs;
++
++ if (xmod->set)
++ retval =
++ nval_set(x_buffer, x_size, xmod->name, xmod->data,
++ xmod->size, xmod->flags);
++ else
++ retval = nval_del(x_buffer, x_size, xmod->name);
++
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ xmod->result = retval;
++
++ return retval;
++}
++
++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
++ void *value, int size)
++{
++ char *buffer = NULL;
++ int result;
++ struct yaffs_ext_tags tags;
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer;
++ int retval = 0;
++
++ if (obj->hdr_chunk < 1)
++ return -ENODATA;
++
++ /* If we know that the object has no xattribs then don't do all the
++ * reading and parsing.
++ */
++ if (obj->xattr_known && !obj->has_xattr) {
++ if (name)
++ return -ENODATA;
++ else
++ return 0;
++ }
++
++ buffer = (char *)yaffs_get_temp_buffer(dev);
++ if (!buffer)
++ return -ENOMEM;
++
++ result =
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
++
++ if (result != YAFFS_OK)
++ retval = -ENOENT;
++ else {
++ x_buffer = buffer + x_offs;
++
++ if (!obj->xattr_known) {
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ }
++
++ if (name)
++ retval = nval_get(x_buffer, x_size, name, value, size);
++ else
++ retval = nval_list(x_buffer, x_size, value, size);
++ }
++ yaffs_release_temp_buffer(dev, (u8 *) buffer);
++ return retval;
++}
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++ const void *value, int size, int flags)
++{
++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
++}
++
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
++{
++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
++}
++
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++ int size)
++{
++ return yaffs_do_xattrib_fetch(obj, name, value, size);
++}
++
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
++{
++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
++}
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
++{
++ u8 *buf;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++
++ if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
++ return;
++
++ dev = in->my_dev;
++ in->lazy_loaded = 0;
++ buf = yaffs_get_temp_buffer(dev);
++
++ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
++ oh = (struct yaffs_obj_hdr *)buf;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ yaffs_set_obj_name_from_oh(in, oh);
++
++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ in->variant.symlink_variant.alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.symlink_variant.alias)
++ alloc_failed = 1; /* Not returned */
++ }
++ yaffs_release_temp_buffer(dev, buf);
++}
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
++ const YCHAR *oh_name, int buff_size)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ if (dev->param.auto_unicode) {
++ if (*oh_name) {
++ /* It is an ASCII name, do an ASCII to
++ * unicode conversion */
++ const char *ascii_oh_name = (const char *)oh_name;
++ int n = buff_size - 1;
++ while (n > 0 && *ascii_oh_name) {
++ *name = *ascii_oh_name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ strncpy(name, oh_name + 1, buff_size - 1);
++ }
++ } else {
++#else
++ (void) dev;
++ {
++#endif
++ strncpy(name, oh_name, buff_size - 1);
++ }
++}
++
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
++ const YCHAR *name)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++
++ int is_ascii;
++ YCHAR *w;
++
++ if (dev->param.auto_unicode) {
++
++ is_ascii = 1;
++ w = name;
++
++ /* Figure out if the name will fit in ascii character set */
++ while (is_ascii && *w) {
++ if ((*w) & 0xff00)
++ is_ascii = 0;
++ w++;
++ }
++
++ if (is_ascii) {
++ /* It is an ASCII name, so convert unicode to ascii */
++ char *ascii_oh_name = (char *)oh_name;
++ int n = YAFFS_MAX_NAME_LENGTH - 1;
++ while (n > 0 && *name) {
++ *ascii_oh_name = *name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ /* Unicode name, so save starting at the second YCHAR */
++ *oh_name = 0;
++ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
++ }
++ } else {
++#else
++ dev = dev;
++ {
++#endif
++ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
++ }
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
++{
++
++ struct yaffs_block_info *bi;
++ struct yaffs_dev *dev = in->my_dev;
++ int prev_chunk_id;
++ int ret_val = 0;
++ int result = 0;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_ext_tags old_tags;
++ const YCHAR *alias = NULL;
++ u8 *buffer = NULL;
++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj_hdr *oh = NULL;
++ loff_t file_size = 0;
++
++ strcpy(old_name, _Y("silly old name"));
++
++ if (in->fake && in != dev->root_dir && !force && !xmod)
++ return ret_val;
++
++ yaffs_check_gc(dev, 0);
++ yaffs_check_obj_details_loaded(in);
++
++ buffer = yaffs_get_temp_buffer(in->my_dev);
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ prev_chunk_id = in->hdr_chunk;
++
++ if (prev_chunk_id > 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
++ buffer, &old_tags);
++
++ yaffs_verify_oh(in, oh, &old_tags, 0);
++ memcpy(old_name, oh->name, sizeof(oh->name));
++ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
++ } else {
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ }
++
++ oh->type = in->variant_type;
++ oh->yst_mode = in->yst_mode;
++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
++
++ yaffs_load_attribs_oh(oh, in);
++
++ if (in->parent)
++ oh->parent_obj_id = in->parent->obj_id;
++ else
++ oh->parent_obj_id = 0;
++
++ if (name && *name) {
++ memset(oh->name, 0, sizeof(oh->name));
++ yaffs_load_oh_from_name(dev, oh->name, name);
++ } else if (prev_chunk_id > 0) {
++ memcpy(oh->name, old_name, sizeof(oh->name));
++ } else {
++ memset(oh->name, 0, sizeof(oh->name));
++ }
++
++ oh->is_shrink = is_shrink;
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Should not happen */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
++ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
++ file_size = in->variant.file_variant.file_size;
++ yaffs_oh_size_load(oh, file_size);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = in->variant.symlink_variant.alias;
++ if (!alias)
++ alias = _Y("no alias");
++ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++ break;
++ }
++
++ /* process any xattrib modifications */
++ if (xmod)
++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
++
++ /* Tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++ in->serial++;
++ new_tags.chunk_id = 0;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number = in->serial;
++
++ /* Add extra info for file header */
++ new_tags.extra_available = 1;
++ new_tags.extra_parent_id = oh->parent_obj_id;
++ new_tags.extra_file_size = file_size;
++ new_tags.extra_is_shrink = oh->is_shrink;
++ new_tags.extra_equiv_id = oh->equiv_id;
++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
++ new_tags.extra_obj_type = in->variant_type;
++ yaffs_verify_oh(in, oh, &new_tags, 1);
++
++ /* Create new chunk in NAND */
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags,
++ (prev_chunk_id > 0) ? 1 : 0);
++
++ if (buffer)
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (new_chunk_id < 0)
++ return new_chunk_id;
++
++ in->hdr_chunk = new_chunk_id;
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ if (!yaffs_obj_cache_dirty(in))
++ in->dirty = 0;
++
++ /* If this was a shrink, then mark the block
++ * that the chunk lives on */
++ if (is_shrink) {
++ bi = yaffs_get_block_info(in->my_dev,
++ new_chunk_id /
++ in->my_dev->param.chunks_per_block);
++ bi->has_shrink_hdr = 1;
++ }
++
++
++ return new_chunk_id;
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
++{
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ struct yaffs_cache *cache;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++ if ((start + n) < dev->data_bytes_per_chunk)
++ n_copy = n;
++ else
++ n_copy = dev->data_bytes_per_chunk - start;
++
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ /* If the chunk is already in the cache or it is less than
++ * a whole chunk or we're using inband tags then use the cache
++ * (if there is caching) else bypass the cache.
++ */
++ if (cache || n_copy != dev->data_bytes_per_chunk ||
++ dev->param.inband_tags) {
++ if (dev->param.n_caches > 0) {
++
++ /* If we can't find the data in the cache,
++ * then load it up. */
++
++ if (!cache) {
++ cache =
++ yaffs_grab_chunk_cache(in->my_dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ cache->n_bytes = 0;
++ }
++
++ yaffs_use_cache(dev, cache, 0);
++
++ cache->locked = 1;
++
++ memcpy(buffer, &cache->data[start], n_copy);
++
++ cache->locked = 0;
++ } else {
++ /* Read into the local buffer then copy.. */
++
++ u8 *local_buffer =
++ yaffs_get_temp_buffer(dev);
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++
++ memcpy(buffer, &local_buffer[start], n_copy);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Read directly into the buffer. */
++ yaffs_rd_data_obj(in, chunk, buffer);
++ }
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ return n_done;
++}
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ int n_writeback;
++ loff_t start_write = offset;
++ int chunk_written = 0;
++ u32 n_bytes_read;
++ loff_t chunk_start;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0 && chunk_written >= 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++
++ if (((loff_t)chunk) *
++ dev->data_bytes_per_chunk + start != offset ||
++ start >= dev->data_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "AddrToChunk of offset %lld gives chunk %d start %d",
++ offset, chunk, start);
++ }
++ chunk++; /* File pos to chunk in file offset */
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++
++ if ((start + n) < dev->data_bytes_per_chunk) {
++ n_copy = n;
++
++ /* Now calculate how many bytes to write back....
++ * If we're overwriting and not writing to then end of
++ * file then we need to write back as much as was there
++ * before.
++ */
++
++ chunk_start = (((loff_t)(chunk - 1)) *
++ dev->data_bytes_per_chunk);
++
++ if (chunk_start > in->variant.file_variant.file_size)
++ n_bytes_read = 0; /* Past end of file */
++ else
++ n_bytes_read =
++ in->variant.file_variant.file_size -
++ chunk_start;
++
++ if (n_bytes_read > dev->data_bytes_per_chunk)
++ n_bytes_read = dev->data_bytes_per_chunk;
++
++ n_writeback =
++ (n_bytes_read >
++ (start + n)) ? n_bytes_read : (start + n);
++
++ if (n_writeback < 0 ||
++ n_writeback > dev->data_bytes_per_chunk)
++ BUG();
++
++ } else {
++ n_copy = dev->data_bytes_per_chunk - start;
++ n_writeback = dev->data_bytes_per_chunk;
++ }
++
++ if (n_copy != dev->data_bytes_per_chunk ||
++ !dev->param.cache_bypass_aligned ||
++ dev->param.inband_tags) {
++ /* An incomplete start or end chunk (or maybe both
++ * start and end chunk), or we're using inband tags,
++ * or we're forcing writes through the cache,
++ * so we want to use the cache buffers.
++ */
++ if (dev->param.n_caches > 0) {
++ struct yaffs_cache *cache;
++
++ /* If we can't find the data in the cache, then
++ * load the cache */
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ if (!cache &&
++ yaffs_check_alloc_available(dev, 1)) {
++ cache = yaffs_grab_chunk_cache(dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ } else if (cache &&
++ !cache->dirty &&
++ !yaffs_check_alloc_available(dev,
++ 1)) {
++ /* Drop the cache if it was a read cache
++ * item and no space check has been made
++ * for it.
++ */
++ cache = NULL;
++ }
++
++ if (cache) {
++ yaffs_use_cache(dev, cache, 1);
++ cache->locked = 1;
++
++ memcpy(&cache->data[start], buffer,
++ n_copy);
++
++ cache->locked = 0;
++ cache->n_bytes = n_writeback;
++
++ if (write_through) {
++ chunk_written =
++ yaffs_wr_data_obj
++ (cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ }
++ } else {
++ chunk_written = -1; /* fail write */
++ }
++ } else {
++ /* An incomplete start or end chunk (or maybe
++ * both start and end chunk). Read into the
++ * local buffer then copy over and write back.
++ */
++
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++ memcpy(&local_buffer[start], buffer, n_copy);
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk,
++ local_buffer,
++ n_writeback, 0);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Write directly from the buffer. */
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk, buffer,
++ dev->data_bytes_per_chunk, 0);
++
++ /* Since we've overwritten the cached data,
++ * we better invalidate it. */
++ yaffs_invalidate_chunk_cache(in, chunk);
++ }
++
++ if (chunk_written >= 0) {
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ }
++
++ /* Update file object */
++
++ if ((start_write + n_done) > in->variant.file_variant.file_size)
++ in->variant.file_variant.file_size = (start_write + n_done);
++
++ in->dirty = 1;
++ return n_done;
++}
++
++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++ yaffs2_handle_hole(in, offset);
++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
++}
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
++{
++
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++ int i;
++ int chunk_id;
++ u32 dummy;
++ int last_del;
++ int start_del;
++
++ if (old_size > 0)
++ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
++ else
++ last_del = 0;
++
++ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
++ &start_del, &dummy);
++ last_del++;
++ start_del++;
++
++ /* Delete backwards so that we don't end up with holes if
++ * power is lost part-way through the operation.
++ */
++ for (i = last_del; i >= start_del; i--) {
++ /* NB this could be optimised somewhat,
++ * eg. could retrieve the tags and write them without
++ * using yaffs_chunk_del
++ */
++
++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
++
++ if (chunk_id < 1)
++ continue;
++
++ if (chunk_id <
++ (dev->internal_start_block * dev->param.chunks_per_block) ||
++ chunk_id >=
++ ((dev->internal_end_block + 1) *
++ dev->param.chunks_per_block)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Found daft chunk_id %d for %d",
++ chunk_id, i);
++ } else {
++ in->n_data_chunks--;
++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
++ }
++ }
++}
++
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
++{
++ int new_full;
++ u32 new_partial;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
++
++ yaffs_prune_chunks(obj, new_size);
++
++ if (new_partial != 0) {
++ int last_chunk = 1 + new_full;
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ /* Rewrite the last chunk with its new size and zero pad */
++ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
++ memset(local_buffer + new_partial, 0,
++ dev->data_bytes_per_chunk - new_partial);
++
++ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
++ new_partial, 1);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++
++ obj->variant.file_variant.file_size = new_size;
++
++ yaffs_prune_tree(dev, &obj->variant.file_variant);
++}
++
++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
++{
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++
++ yaffs_flush_file_cache(in);
++ yaffs_invalidate_whole_cache(in);
++
++ yaffs_check_gc(dev, 0);
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ if (new_size == old_size)
++ return YAFFS_OK;
++
++ if (new_size > old_size) {
++ yaffs2_handle_hole(in, new_size);
++ in->variant.file_variant.file_size = new_size;
++ } else {
++ /* new_size < old_size */
++ yaffs_resize_file_down(in, new_size);
++ }
++
++ /* Write a new object header to reflect the resize.
++ * show we've shrunk the file, if need be
++ * Do this only if the file is not in the deleted directories
++ * and is not shadowed.
++ */
++ if (in->parent &&
++ !in->is_shadowed &&
++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ in->parent->obj_id != YAFFS_OBJECTID_DELETED)
++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
++
++ return YAFFS_OK;
++}
++
++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
++{
++ if (!in->dirty)
++ return YAFFS_OK;
++
++ yaffs_flush_file_cache(in);
++
++ if (data_sync)
++ return YAFFS_OK;
++
++ if (update_time)
++ yaffs_load_current_time(in, 0, 0);
++
++ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
++ YAFFS_OK : YAFFS_FAIL;
++}
++
++
++/* yaffs_del_file deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
++{
++ int ret_val;
++ int del_now = 0;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!in->my_inode)
++ del_now = 1;
++
++ if (del_now) {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->del_dir,
++ _Y("deleted"), 0, 0);
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: immediate deletion of file %d",
++ in->obj_id);
++ in->deleted = 1;
++ in->my_dev->n_deleted_files++;
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++ yaffs_soft_del_file(in);
++ } else {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++ return ret_val;
++}
++
++static int yaffs_del_file(struct yaffs_obj *in)
++{
++ int ret_val = YAFFS_OK;
++ int deleted; /* Need to cache value on stack if in is freed */
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++
++ if (in->n_data_chunks > 0) {
++ /* Use soft deletion if there is data in the file.
++ * That won't be the case if it has been resized to zero.
++ */
++ if (!in->unlinked)
++ ret_val = yaffs_unlink_file_if_needed(in);
++
++ deleted = in->deleted;
++
++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
++ in->deleted = 1;
++ deleted = 1;
++ in->my_dev->n_deleted_files++;
++ yaffs_soft_del_file(in);
++ }
++ return deleted ? YAFFS_OK : YAFFS_FAIL;
++ } else {
++ /* The file has no data chunks so we toss it immediately */
++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
++ in->variant.file_variant.top = NULL;
++ yaffs_generic_obj_del(in);
++
++ return YAFFS_OK;
++ }
++}
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
++{
++ return (obj &&
++ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++ !(list_empty(&obj->variant.dir_variant.children));
++}
++
++static int yaffs_del_dir(struct yaffs_obj *obj)
++{
++ /* First check that the directory is empty. */
++ if (yaffs_is_non_empty_dir(obj))
++ return YAFFS_FAIL;
++
++ return yaffs_generic_obj_del(obj);
++}
++
++static int yaffs_del_symlink(struct yaffs_obj *in)
++{
++ kfree(in->variant.symlink_variant.alias);
++ in->variant.symlink_variant.alias = NULL;
++
++ return yaffs_generic_obj_del(in);
++}
++
++static int yaffs_del_link(struct yaffs_obj *in)
++{
++ /* remove this hardlink from the list associated with the equivalent
++ * object
++ */
++ list_del_init(&in->hard_links);
++ return yaffs_generic_obj_del(in);
++}
++
++int yaffs_del_obj(struct yaffs_obj *obj)
++{
++ int ret_val = -1;
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ ret_val = yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!list_empty(&obj->variant.dir_variant.dirty)) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Remove object %d from dirty directories",
++ obj->obj_id);
++ list_del_init(&obj->variant.dir_variant.dirty);
++ }
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ ret_val = yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ ret_val = yaffs_del_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ ret_val = yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ ret_val = 0;
++ break; /* should not happen. */
++ }
++ return ret_val;
++}
++
++
++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
++ struct yaffs_obj *to_dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_add_obj_to_dir(to_dir, obj);
++ }
++}
++
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type)
++{
++ /* Tear down the old variant */
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ /* Nuke file data */
++ yaffs_resize_file(obj, 0);
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Put the children in lost and found. */
++ yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
++ if (!list_empty(&obj->variant.dir_variant.dirty))
++ list_del_init(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ /* Nuke symplink data */
++ kfree(obj->variant.symlink_variant.alias);
++ obj->variant.symlink_variant.alias = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ list_del_init(&obj->hard_links);
++ break;
++ default:
++ break;
++ }
++
++ memset(&obj->variant, 0, sizeof(obj->variant));
++
++ /*Set up new variant if the memset is not enough. */
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ default:
++ break;
++ }
++
++ obj->variant_type = type;
++
++ return obj;
++
++}
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj)
++{
++ int del_now = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (!obj->my_inode)
++ del_now = 1;
++
++ yaffs_update_parent(obj->parent);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ return yaffs_del_link(obj);
++ } else if (!list_empty(&obj->hard_links)) {
++ /* Curve ball: We're unlinking an object that has a hardlink.
++ *
++ * This problem arises because we are not strictly following
++ * The Linux link/inode model.
++ *
++ * We can't really delete the object.
++ * Instead, we do the following:
++ * - Select a hardlink.
++ * - Unhook it from the hard links
++ * - Move it from its parent directory so that the rename works.
++ * - Rename the object to the hardlink's name.
++ * - Delete the hardlink
++ */
++
++ struct yaffs_obj *hl;
++ struct yaffs_obj *parent;
++ int ret_val;
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
++ hard_links);
++
++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++ parent = hl->parent;
++
++ list_del_init(&hl->hard_links);
++
++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
++
++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
++
++ if (ret_val == YAFFS_OK)
++ ret_val = yaffs_generic_obj_del(hl);
++
++ return ret_val;
++
++ } else if (del_now) {
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ list_del_init(&obj->variant.dir_variant.dirty);
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ return yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ return YAFFS_FAIL;
++ }
++ } else if (yaffs_is_non_empty_dir(obj)) {
++ return YAFFS_FAIL;
++ } else {
++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++}
++
++static int yaffs_unlink_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->unlink_allowed)
++ return yaffs_unlink_worker(obj);
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
++{
++ struct yaffs_obj *obj;
++
++ obj = yaffs_find_by_name(dir, name);
++ return yaffs_unlink_obj(obj);
++}
++
++/* Note:
++ * If old_name is NULL then we take old_dir as the object to be renamed.
++ */
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
++ struct yaffs_obj *new_dir, const YCHAR *new_name)
++{
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *existing_target = NULL;
++ int force = 0;
++ int result;
++ struct yaffs_dev *dev;
++
++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ dev = old_dir->my_dev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ /* Special case for case insemsitive systems.
++ * While look-up is case insensitive, the name isn't.
++ * Therefore we might want to change x.txt to X.txt
++ */
++ if (old_dir == new_dir &&
++ old_name && new_name &&
++ strcmp(old_name, new_name) == 0)
++ force = 1;
++#endif
++
++ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ /* ENAMETOOLONG */
++ return YAFFS_FAIL;
++
++ if (old_name)
++ obj = yaffs_find_by_name(old_dir, old_name);
++ else{
++ obj = old_dir;
++ old_dir = obj->parent;
++ }
++
++ if (obj && obj->rename_allowed) {
++ /* Now handle an existing target, if there is one */
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++ if (yaffs_is_non_empty_dir(existing_target)) {
++ return YAFFS_FAIL; /* ENOTEMPTY */
++ } else if (existing_target && existing_target != obj) {
++ /* Nuke the target first, using shadowing,
++ * but only if it isn't the same object.
++ *
++ * Note we must disable gc here otherwise it can mess
++ * up the shadowing.
++ *
++ */
++ dev->gc_disable = 1;
++ yaffs_change_obj_name(obj, new_dir, new_name, force,
++ existing_target->obj_id);
++ existing_target->is_shadowed = 1;
++ yaffs_unlink_obj(existing_target);
++ dev->gc_disable = 0;
++ }
++
++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
++
++ yaffs_update_parent(old_dir);
++ if (new_dir != old_dir)
++ yaffs_update_parent(new_dir);
++
++ return result;
++ }
++ return YAFFS_FAIL;
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning)
++{
++ struct yaffs_obj *obj;
++
++ if (backward_scanning) {
++ /* Handle YAFFS2 case (backward scanning)
++ * If the shadowed object exists then ignore.
++ */
++ obj = yaffs_find_by_number(dev, obj_id);
++ if (obj)
++ return;
++ }
++
++ /* Let's create it (if it does not exist) assuming it is a file so that
++ * it can do shrinking etc.
++ * We put it in unlinked dir to be cleaned up after the scanning
++ */
++ obj =
++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
++ if (!obj)
++ return;
++ obj->is_shadowed = 1;
++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
++ obj->variant.file_variant.shrink_size = 0;
++ obj->valid = 1; /* So that we don't read any other info. */
++}
++
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
++{
++ struct list_head *lh;
++ struct list_head *save;
++ struct yaffs_obj *hl;
++ struct yaffs_obj *in;
++
++ list_for_each_safe(lh, save, hard_list) {
++ hl = list_entry(lh, struct yaffs_obj, hard_links);
++ in = yaffs_find_by_number(dev,
++ hl->variant.hardlink_variant.equiv_id);
++
++ if (in) {
++ /* Add the hardlink pointers */
++ hl->variant.hardlink_variant.equiv_obj = in;
++ list_add(&hl->hard_links, &in->hard_links);
++ } else {
++ /* Todo Need to report/handle this better.
++ * Got a problem... hardlink to a non-existant object
++ */
++ hl->variant.hardlink_variant.equiv_obj = NULL;
++ INIT_LIST_HEAD(&hl->hard_links);
++ }
++ }
++}
++
++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
++{
++ /*
++ * Sort out state of unlinked and deleted objects after scanning.
++ */
++ struct list_head *i;
++ struct list_head *n;
++ struct yaffs_obj *l;
++
++ if (dev->read_only)
++ return;
++
++ /* Soft delete all the unlinked files */
++ list_for_each_safe(i, n,
++ &dev->unlinked_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++
++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ * This code assumes that we don't ever change the current relationships
++ * between directories:
++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
++ * lost-n-found->parent == root_dir
++ *
++ * This fixes the problem where directories might have inadvertently been
++ * deleted leaving the object "hanging" without being rooted in the
++ * directory tree.
++ */
++
++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++ return (obj == dev->del_dir ||
++ obj == dev->unlinked_dir || obj == dev->root_dir);
++}
++
++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_obj *parent;
++ int i;
++ struct list_head *lh;
++ struct list_head *n;
++ int depth_limit;
++ int hanging;
++
++ if (dev->read_only)
++ return;
++
++ /* Iterate through the objects in each hash entry,
++ * looking at each object.
++ * Make sure it is rooted.
++ */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ parent = obj->parent;
++
++ if (yaffs_has_null_parent(dev, obj)) {
++ /* These directories are not hanging */
++ hanging = 0;
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ hanging = 1;
++ } else if (yaffs_has_null_parent(dev, parent)) {
++ hanging = 0;
++ } else {
++ /*
++ * Need to follow the parent chain to
++ * see if it is hanging.
++ */
++ hanging = 0;
++ depth_limit = 100;
++
++ while (parent != dev->root_dir &&
++ parent->parent &&
++ parent->parent->variant_type ==
++ YAFFS_OBJECT_TYPE_DIRECTORY &&
++ depth_limit > 0) {
++ parent = parent->parent;
++ depth_limit--;
++ }
++ if (parent != dev->root_dir)
++ hanging = 1;
++ }
++ if (hanging) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Hanging object %d moved to lost and found",
++ obj->obj_id);
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++ }
++ }
++ }
++}
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_del_dir_contents(struct yaffs_obj *dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ BUG();
++
++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
++ yaffs_del_dir_contents(obj);
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Deleting lost_found object %d",
++ obj->obj_id);
++ yaffs_unlink_obj(obj);
++ }
++}
++
++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
++{
++ yaffs_del_dir_contents(dev->lost_n_found);
++}
++
++
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
++ const YCHAR *name)
++{
++ int sum;
++ struct list_head *i;
++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj *l;
++
++ if (!name)
++ return NULL;
++
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: null pointer directory"
++ );
++ BUG();
++ return NULL;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: non-directory"
++ );
++ BUG();
++ }
++
++ sum = yaffs_calc_name_sum(name);
++
++ list_for_each(i, &directory->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++
++ if (l->parent != directory)
++ BUG();
++
++ yaffs_check_obj_details_loaded(l);
++
++ /* Special case for lost-n-found */
++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
++ return l;
++ } else if (l->sum == sum || l->hdr_chunk <= 0) {
++ /* LostnFound chunk called Objxxx
++ * Do a real check
++ */
++ yaffs_get_obj_name(l, buffer,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
++ return l;
++ }
++ }
++ return NULL;
++}
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ obj = obj->variant.hardlink_variant.equiv_obj;
++ yaffs_check_obj_details_loaded(obj);
++ }
++ return obj;
++}
++
++/*
++ * A note or two on object names.
++ * * If the object name is missing, we then make one up in the form objnnn
++ *
++ * * ASCII names are stored in the object header's name field from byte zero
++ * * Unicode names are historically stored starting from byte zero.
++ *
++ * Then there are automatic Unicode names...
++ * The purpose of these is to save names in a way that can be read as
++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
++ * system to share files.
++ *
++ * These automatic unicode are stored slightly differently...
++ * - If the name can fit in the ASCII character space then they are saved as
++ * ascii names as per above.
++ * - If the name needs Unicode then the name is saved in Unicode
++ * starting at oh->name[1].
++
++ */
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size)
++{
++ /* Create an object name if we could not find one. */
++ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
++ YCHAR local_name[20];
++ YCHAR num_string[20];
++ YCHAR *x = &num_string[19];
++ unsigned v = obj->obj_id;
++ num_string[19] = 0;
++ while (v > 0) {
++ x--;
++ *x = '0' + (v % 10);
++ v /= 10;
++ }
++ /* make up a name */
++ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
++ strcat(local_name, x);
++ strncpy(name, local_name, buffer_size - 1);
++ }
++}
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
++{
++ memset(name, 0, buffer_size * sizeof(YCHAR));
++ yaffs_check_obj_details_loaded(obj);
++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
++ } else if (obj->short_name[0]) {
++ strcpy(name, obj->short_name);
++ } else if (obj->hdr_chunk > 0) {
++ int result;
++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
++
++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
++
++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
++
++ if (obj->hdr_chunk > 0) {
++ result = yaffs_rd_chunk_tags_nand(obj->my_dev,
++ obj->hdr_chunk,
++ buffer, NULL);
++ }
++ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
++ buffer_size);
++
++ yaffs_release_temp_buffer(obj->my_dev, buffer);
++ }
++
++ yaffs_fix_null_name(obj, name, buffer_size);
++
++ return strnlen(name, YAFFS_MAX_NAME_LENGTH);
++}
++
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
++{
++ /* Dereference any hard linking */
++ obj = yaffs_get_equivalent_obj(obj);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ return obj->variant.file_variant.file_size;
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ if (!obj->variant.symlink_variant.alias)
++ return 0;
++ return strnlen(obj->variant.symlink_variant.alias,
++ YAFFS_MAX_ALIAS_LENGTH);
++ } else {
++ /* Only a directory should drop through to here */
++ return obj->my_dev->data_bytes_per_chunk;
++ }
++}
++
++int yaffs_get_obj_link_count(struct yaffs_obj *obj)
++{
++ int count = 0;
++ struct list_head *i;
++
++ if (!obj->unlinked)
++ count++; /* the object itself */
++
++ list_for_each(i, &obj->hard_links)
++ count++; /* add the hard links; */
++
++ return count;
++}
++
++int yaffs_get_obj_inode(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ return obj->obj_id;
++}
++
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return DT_DIR;
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return DT_LNK;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ if (S_ISFIFO(obj->yst_mode))
++ return DT_FIFO;
++ if (S_ISCHR(obj->yst_mode))
++ return DT_CHR;
++ if (S_ISBLK(obj->yst_mode))
++ return DT_BLK;
++ if (S_ISSOCK(obj->yst_mode))
++ return DT_SOCK;
++ return DT_REG;
++ break;
++ default:
++ return DT_REG;
++ break;
++ }
++}
++
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
++ return yaffs_clone_str(obj->variant.symlink_variant.alias);
++ else
++ return yaffs_clone_str(_Y(""));
++}
++
++/*--------------------------- Initialisation code -------------------------- */
++
++static int yaffs_check_dev_fns(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++ struct yaffs_tags_handler *tagger = &dev->tagger;
++
++ /* Common functions, gotta have */
++ if (!drv->drv_read_chunk_fn ||
++ !drv->drv_write_chunk_fn ||
++ !drv->drv_erase_fn)
++ return 0;
++
++ if (dev->param.is_yaffs2 &&
++ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
++ return 0;
++
++ /* Install the default tags marshalling functions if needed. */
++ yaffs_tags_compat_install(dev);
++ yaffs_tags_marshall_install(dev);
++
++ /* Check we now have the marshalling functions required. */
++ if (!tagger->write_chunk_tags_fn ||
++ !tagger->read_chunk_tags_fn ||
++ !tagger->query_block_fn ||
++ !tagger->mark_bad_fn)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs_create_initial_dir(struct yaffs_dev *dev)
++{
++ /* Initialise the unlinked, deleted, root and lost+found directories */
++ dev->lost_n_found = dev->root_dir = NULL;
++ dev->unlinked_dir = dev->del_dir = NULL;
++ dev->unlinked_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++ dev->del_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++ dev->root_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
++ YAFFS_ROOT_MODE | S_IFDIR);
++ dev->lost_n_found =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
++ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
++ && dev->del_dir) {
++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++/* Low level init.
++ * Typically only used by yaffs_guts_initialise, but also used by the
++ * Low level yaffs driver tests.
++ */
++
++int yaffs_guts_ll_init(struct yaffs_dev *dev)
++{
++
++
++ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
++
++ if (!dev) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Need a device"
++ );
++ return YAFFS_FAIL;
++ }
++
++ if (dev->ll_init)
++ return YAFFS_OK;
++
++ dev->internal_start_block = dev->param.start_block;
++ dev->internal_end_block = dev->param.end_block;
++ dev->block_offset = 0;
++ dev->chunk_offset = 0;
++ dev->n_free_chunks = 0;
++
++ dev->gc_block = 0;
++
++ if (dev->param.start_block == 0) {
++ dev->internal_start_block = dev->param.start_block + 1;
++ dev->internal_end_block = dev->param.end_block + 1;
++ dev->block_offset = 1;
++ dev->chunk_offset = dev->param.chunks_per_block;
++ }
++
++ /* Check geometry parameters. */
++
++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 1024) ||
++ (!dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 512) ||
++ (dev->param.inband_tags && !dev->param.is_yaffs2) ||
++ dev->param.chunks_per_block < 2 ||
++ dev->param.n_reserved_blocks < 2 ||
++ dev->internal_start_block <= 0 ||
++ dev->internal_end_block <= 0 ||
++ dev->internal_end_block <=
++ (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
++ ) {
++ /* otherwise it is too small */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
++ dev->param.total_bytes_per_chunk,
++ dev->param.is_yaffs2 ? "2" : "",
++ dev->param.inband_tags);
++ return YAFFS_FAIL;
++ }
++
++ /* Sort out space for inband tags, if required */
++ if (dev->param.inband_tags)
++ dev->data_bytes_per_chunk =
++ dev->param.total_bytes_per_chunk -
++ sizeof(struct yaffs_packed_tags2_tags_only);
++ else
++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
++
++ /* Got the right mix of functions? */
++ if (!yaffs_check_dev_fns(dev)) {
++ /* Function missing */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "device function(s) missing or wrong");
++
++ return YAFFS_FAIL;
++ }
++
++ if (yaffs_init_nand(dev) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev)
++{
++ int i;
++ enum yaffs_block_state state;
++ u32 dummy;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if(dev->is_mounted)
++ return YAFFS_FAIL;
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ yaffs_query_init_block_state(dev, i, &state, &dummy);
++ if (state != YAFFS_BLOCK_STATE_DEAD)
++ yaffs_erase_block(dev, i);
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_initialise(struct yaffs_dev *dev)
++{
++ int init_failed = 0;
++ unsigned x;
++ int bits;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if (dev->is_mounted) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
++ return YAFFS_FAIL;
++ }
++
++ dev->is_mounted = 1;
++
++ /* OK now calculate a few things for the device */
++
++ /*
++ * Calculate all the chunk size manipulation numbers:
++ */
++ x = dev->data_bytes_per_chunk;
++ /* We always use dev->chunk_shift and dev->chunk_div */
++ dev->chunk_shift = calc_shifts(x);
++ x >>= dev->chunk_shift;
++ dev->chunk_div = x;
++ /* We only use chunk mask if chunk_div is 1 */
++ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
++
++ /*
++ * Calculate chunk_grp_bits.
++ * We need to find the next power of 2 > than internal_end_block
++ */
++
++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
++
++ bits = calc_shifts_ceiling(x);
++
++ /* Set up tnode width if wide tnodes are enabled. */
++ if (!dev->param.wide_tnodes_disabled) {
++ /* bits must be even so that we end up with 32-bit words */
++ if (bits & 1)
++ bits++;
++ if (bits < 16)
++ dev->tnode_width = 16;
++ else
++ dev->tnode_width = bits;
++ } else {
++ dev->tnode_width = 16;
++ }
++
++ dev->tnode_mask = (1 << dev->tnode_width) - 1;
++
++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++ * so if the bitwidth of the
++ * chunk range we're using is greater than 16 we need
++ * to figure out chunk shift and chunk_grp_size
++ */
++
++ if (bits <= dev->tnode_width)
++ dev->chunk_grp_bits = 0;
++ else
++ dev->chunk_grp_bits = bits - dev->tnode_width;
++
++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
++ if (dev->tnode_size < sizeof(struct yaffs_tnode))
++ dev->tnode_size = sizeof(struct yaffs_tnode);
++
++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
++
++ if (dev->param.chunks_per_block < dev->chunk_grp_size) {
++ /* We have a problem because the soft delete won't work if
++ * the chunk group size > chunks per block.
++ * This can be remedied by using larger "virtual blocks".
++ */
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
++
++ return YAFFS_FAIL;
++ }
++
++ /* Finished verifying the device, continue with initialisation */
++
++ /* More device initialisation */
++ dev->all_gcs = 0;
++ dev->passive_gc_count = 0;
++ dev->oldest_dirty_gc_count = 0;
++ dev->bg_gcs = 0;
++ dev->gc_block_finder = 0;
++ dev->buffered_block = -1;
++ dev->doing_buffered_block_rewrite = 0;
++ dev->n_deleted_files = 0;
++ dev->n_bg_deletions = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_ecc_fixed = 0;
++ dev->n_ecc_unfixed = 0;
++ dev->n_tags_ecc_fixed = 0;
++ dev->n_tags_ecc_unfixed = 0;
++ dev->n_erase_failures = 0;
++ dev->n_erased_blocks = 0;
++ dev->gc_disable = 0;
++ dev->has_pending_prioritised_gc = 1;
++ /* Assume the worst for now, will get fixed on first GC */
++ INIT_LIST_HEAD(&dev->dirty_dirs);
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++
++ /* Initialise temporary buffers and caches. */
++ if (!yaffs_init_tmp_buffers(dev))
++ init_failed = 1;
++
++ dev->cache = NULL;
++ dev->gc_cleanup_list = NULL;
++
++ if (!init_failed && dev->param.n_caches > 0) {
++ int i;
++ void *buf;
++ int cache_bytes =
++ dev->param.n_caches * sizeof(struct yaffs_cache);
++
++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
++
++ dev->cache = kmalloc(cache_bytes, GFP_NOFS);
++
++ buf = (u8 *) dev->cache;
++
++ if (dev->cache)
++ memset(dev->cache, 0, cache_bytes);
++
++ for (i = 0; i < dev->param.n_caches && buf; i++) {
++ dev->cache[i].object = NULL;
++ dev->cache[i].last_use = 0;
++ dev->cache[i].dirty = 0;
++ dev->cache[i].data = buf =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ }
++ if (!buf)
++ init_failed = 1;
++
++ dev->cache_last_use = 0;
++ }
++
++ dev->cache_hits = 0;
++
++ if (!init_failed) {
++ dev->gc_cleanup_list =
++ kmalloc(dev->param.chunks_per_block * sizeof(u32),
++ GFP_NOFS);
++ if (!dev->gc_cleanup_list)
++ init_failed = 1;
++ }
++
++ if (dev->param.is_yaffs2)
++ dev->param.use_header_file_size = 1;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && dev->param.is_yaffs2 &&
++ !dev->param.disable_summary &&
++ !yaffs_summary_init(dev))
++ init_failed = 1;
++
++ if (!init_failed) {
++ /* Now scan the flash. */
++ if (dev->param.is_yaffs2) {
++ if (yaffs2_checkpt_restore(dev)) {
++ yaffs_check_obj_details_loaded(dev->root_dir);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT |
++ YAFFS_TRACE_MOUNT,
++ "yaffs: restored from checkpoint"
++ );
++ } else {
++
++ /* Clean up the mess caused by an aborted
++ * checkpoint load then scan backwards.
++ */
++ yaffs_deinit_blocks(dev);
++
++ yaffs_deinit_tnodes_and_objs(dev);
++
++ dev->n_erased_blocks = 0;
++ dev->n_free_chunks = 0;
++ dev->alloc_block = -1;
++ dev->alloc_page = -1;
++ dev->n_deleted_files = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_bg_deletions = 0;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed
++ && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && !yaffs2_scan_backwards(dev))
++ init_failed = 1;
++ }
++ } else if (!yaffs1_scan(dev)) {
++ init_failed = 1;
++ }
++
++ yaffs_strip_deleted_objs(dev);
++ yaffs_fix_hanging_objs(dev);
++ if (dev->param.empty_lost_n_found)
++ yaffs_empty_l_n_f(dev);
++ }
++
++ if (init_failed) {
++ /* Clean up the mess */
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() aborted.");
++
++ yaffs_deinitialise(dev);
++ return YAFFS_FAIL;
++ }
++
++ /* Zero out stats */
++ dev->n_page_reads = 0;
++ dev->n_page_writes = 0;
++ dev->n_erasures = 0;
++ dev->n_gc_copies = 0;
++ dev->n_retried_writes = 0;
++
++ dev->n_retired_blocks = 0;
++
++ yaffs_verify_free_chunks(dev);
++ yaffs_verify_blocks(dev);
++
++ /* Clean up any aborted checkpoint data */
++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() done.");
++ return YAFFS_OK;
++}
++
++void yaffs_deinitialise(struct yaffs_dev *dev)
++{
++ if (dev->is_mounted) {
++ int i;
++
++ yaffs_deinit_blocks(dev);
++ yaffs_deinit_tnodes_and_objs(dev);
++ yaffs_summary_deinit(dev);
++
++ if (dev->param.n_caches > 0 && dev->cache) {
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ kfree(dev->cache[i].data);
++ dev->cache[i].data = NULL;
++ }
++
++ kfree(dev->cache);
++ dev->cache = NULL;
++ }
++
++ kfree(dev->gc_cleanup_list);
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ kfree(dev->temp_buffer[i].buffer);
++
++ dev->is_mounted = 0;
++
++ yaffs_deinit_nand(dev);
++ }
++}
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev)
++{
++ int n_free = 0;
++ int b;
++ struct yaffs_block_info *blk;
++
++ blk = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++ switch (blk->block_state) {
++ case YAFFS_BLOCK_STATE_EMPTY:
++ case YAFFS_BLOCK_STATE_ALLOCATING:
++ case YAFFS_BLOCK_STATE_COLLECTING:
++ case YAFFS_BLOCK_STATE_FULL:
++ n_free +=
++ (dev->param.chunks_per_block - blk->pages_in_use +
++ blk->soft_del_pages);
++ break;
++ default:
++ break;
++ }
++ blk++;
++ }
++ return n_free;
++}
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
++{
++ /* This is what we report to the outside world */
++ int n_free;
++ int n_dirty_caches;
++ int blocks_for_checkpt;
++ int i;
++
++ n_free = dev->n_free_chunks;
++ n_free += dev->n_deleted_files;
++
++ /* Now count and subtract the number of dirty chunks in the cache. */
++
++ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].dirty)
++ n_dirty_caches++;
++ }
++
++ n_free -= n_dirty_caches;
++
++ n_free -=
++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
++
++ /* Now figure checkpoint space and report that... */
++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
++
++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
++
++ if (n_free < 0)
++ n_free = 0;
++
++ return n_free;
++}
++
++
++
++/*
++ * Marshalling functions to get loff_t file sizes into and out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
++{
++ oh->file_size_low = (fsize & 0xFFFFFFFF);
++ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
++}
++
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
++{
++ loff_t retval;
++
++ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
++ retval = (((loff_t) oh->file_size_high) << 32) |
++ (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
++ else
++ retval = (loff_t) oh->file_size_low;
++
++ return retval;
++}
++
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
++{
++ int i;
++ struct yaffs_block_info *bi;
++ int s;
++
++ for(i = 0; i < 10; i++)
++ bs[i] = 0;
++
++ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ bi = yaffs_get_block_info(dev, i);
++ s = bi->block_state;
++ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
++ bs[0]++;
++ else
++ bs[s]++;
++ }
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_guts.h linux-3.13.11/fs/yaffs2/yaffs_guts.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_guts.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,1007 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "yportenv.h"
++
++#define YAFFS_OK 1
++#define YAFFS_FAIL 0
++
++/* Give us a Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xff
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC 0x5941ff53
++
++/*
++ * Tnodes form a tree with the tnodes in "levels"
++ * Levels greater than 0 hold 8 slots which point to other tnodes.
++ * Those at level 0 hold 16 slots which point to chunks in NAND.
++ *
++ * A maximum level of 8 thust supports files of size up to:
++ *
++ * 2^(3*MAX_LEVEL+4)
++ *
++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
++ * a maximum file size of around 512Gbytees with 2k chunks.
++ */
++#define YAFFS_NTNODES_LEVEL0 16
++#define YAFFS_TNODES_LEVEL0_BITS 4
++#define YAFFS_TNODES_LEVEL0_MASK 0xf
++
++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK 0x7
++#define YAFFS_TNODES_MAX_LEVEL 8
++#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
++ YAFFS_TNODES_INTERNAL_BITS * \
++ YAFFS_TNODES_MAX_LEVEL)
++#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
++
++#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
++
++/* Constants for YAFFS1 mode */
++#define YAFFS_BYTES_PER_SPARE 16
++#define YAFFS_BYTES_PER_CHUNK 512
++#define YAFFS_CHUNK_SIZE_SHIFT 9
++#define YAFFS_CHUNKS_PER_BLOCK 32
++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
++
++
++
++#define YAFFS_ALLOCATION_NOBJECTS 100
++#define YAFFS_ALLOCATION_NTNODES 100
++#define YAFFS_ALLOCATION_NLINKS 100
++
++#define YAFFS_NOBJECT_BUCKETS 256
++
++#define YAFFS_OBJECT_SPACE 0x40000
++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
++
++/* Binary data version stamps */
++#define YAFFS_SUMMARY_VERSION 1
++#define YAFFS_CHECKPOINT_VERSION 7
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH 127
++#define YAFFS_MAX_ALIAS_LENGTH 79
++#else
++#define YAFFS_MAX_NAME_LENGTH 255
++#define YAFFS_MAX_ALIAS_LENGTH 159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH 15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT 1
++#define YAFFS_OBJECTID_LOSTNFOUND 2
++#define YAFFS_OBJECTID_UNLINKED 3
++#define YAFFS_OBJECTID_DELETED 4
++
++/* Fake object Id for summary data */
++#define YAFFS_OBJECTID_SUMMARY 0x10
++
++/* Pseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
++
++#define YAFFS_MAX_SHORT_OP_CACHES 20
++
++#define YAFFS_N_TEMP_BUFFERS 6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS (5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
++
++/* ChunkCache is used for short read/write operations.*/
++struct yaffs_cache {
++ struct yaffs_obj *object;
++ int chunk_id;
++ int last_use;
++ int dirty;
++ int n_bytes; /* Only valid if the cache is dirty */
++ int locked; /* Can't push out or flush while locked. */
++ u8 *data;
++};
++
++/* yaffs1 tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
++ * otherwise the structure size will get blown out.
++ */
++
++struct yaffs_tags {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes_lsb:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 n_bytes_msb:2;
++};
++
++union yaffs_tags_union {
++ struct yaffs_tags as_tags;
++ u8 as_bytes[8];
++};
++
++
++/* Stuff used for extended tags in YAFFS2 */
++
++enum yaffs_ecc_result {
++ YAFFS_ECC_RESULT_UNKNOWN,
++ YAFFS_ECC_RESULT_NO_ERROR,
++ YAFFS_ECC_RESULT_FIXED,
++ YAFFS_ECC_RESULT_UNFIXED
++};
++
++enum yaffs_obj_type {
++ YAFFS_OBJECT_TYPE_UNKNOWN,
++ YAFFS_OBJECT_TYPE_FILE,
++ YAFFS_OBJECT_TYPE_SYMLINK,
++ YAFFS_OBJECT_TYPE_DIRECTORY,
++ YAFFS_OBJECT_TYPE_HARDLINK,
++ YAFFS_OBJECT_TYPE_SPECIAL
++};
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++struct yaffs_ext_tags {
++ unsigned chunk_used; /* Status of the chunk: used or unused */
++ unsigned obj_id; /* If 0 this is not used */
++ unsigned chunk_id; /* If 0 this is a header, else a data chunk */
++ unsigned n_bytes; /* Only valid for data chunks */
++
++ /* The following stuff only has meaning when we read */
++ enum yaffs_ecc_result ecc_result;
++ unsigned block_bad;
++
++ /* YAFFS 1 stuff */
++ unsigned is_deleted; /* The chunk is marked deleted */
++ unsigned serial_number; /* Yaffs1 2-bit serial number */
++
++ /* YAFFS2 stuff */
++ unsigned seq_number; /* The sequence number of this block */
++
++ /* Extra info if this is an object header (YAFFS2 only) */
++
++ unsigned extra_available; /* Extra info available if not zero */
++ unsigned extra_parent_id; /* The parent object */
++ unsigned extra_is_shrink; /* Is it a shrink header? */
++ unsigned extra_shadows; /* Does this shadow another object? */
++
++ enum yaffs_obj_type extra_obj_type; /* What object type? */
++
++ loff_t extra_file_size; /* Length if it is a file */
++ unsigned extra_equiv_id; /* Equivalent object for a hard link */
++};
++
++/* Spare structure for YAFFS1 */
++struct yaffs_spare {
++ u8 tb0;
++ u8 tb1;
++ u8 tb2;
++ u8 tb3;
++ u8 page_status; /* set to 0 to delete the chunk */
++ u8 block_status;
++ u8 tb4;
++ u8 tb5;
++ u8 ecc1[3];
++ u8 tb6;
++ u8 tb7;
++ u8 ecc2[3];
++};
++
++/*Special structure for passing through to mtd */
++struct yaffs_nand_spare {
++ struct yaffs_spare spare;
++ int eccres1;
++ int eccres2;
++};
++
++/* Block data in RAM */
++
++enum yaffs_block_state {
++ YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++ YAFFS_BLOCK_STATE_SCANNING,
++ /* Being scanned */
++
++ YAFFS_BLOCK_STATE_NEEDS_SCAN,
++ /* The block might have something on it (ie it is allocating or full,
++ * perhaps empty) but it needs to be scanned to determine its true
++ * state.
++ * This state is only valid during scanning.
++ * NB We tolerate empty because the pre-scanner might be incapable of
++ * deciding
++ * However, if this state is returned on a YAFFS2 device,
++ * then we expect a sequence number
++ */
++
++ YAFFS_BLOCK_STATE_EMPTY,
++ /* This block is empty */
++
++ YAFFS_BLOCK_STATE_ALLOCATING,
++ /* This block is partially allocated.
++ * At least one page holds valid data.
++ * This is the one currently being used for page
++ * allocation. Should never be more than one of these.
++ * If a block is only partially allocated at mount it is treated as
++ * full.
++ */
++
++ YAFFS_BLOCK_STATE_FULL,
++ /* All the pages in this block have been allocated.
++ * If a block was only partially allocated when mounted we treat
++ * it as fully allocated.
++ */
++
++ YAFFS_BLOCK_STATE_DIRTY,
++ /* The block was full and now all chunks have been deleted.
++ * Erase me, reuse me.
++ */
++
++ YAFFS_BLOCK_STATE_CHECKPOINT,
++ /* This block is assigned to holding checkpoint data. */
++
++ YAFFS_BLOCK_STATE_COLLECTING,
++ /* This block is being garbage collected */
++
++ YAFFS_BLOCK_STATE_DEAD
++ /* This block has failed and is not in use */
++};
++
++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++struct yaffs_block_info {
++
++ s32 soft_del_pages:10; /* number of soft deleted pages */
++ s32 pages_in_use:10; /* number of pages in use */
++ u32 block_state:4; /* One of the above block states. */
++ /* NB use unsigned because enum is sometimes
++ * an int */
++ u32 needs_retiring:1; /* Data has failed on this block, */
++ /*need to get valid data off and retire*/
++ u32 skip_erased_check:1;/* Skip the erased check on this block */
++ u32 gc_prioritise:1; /* An ECC check or blank check has failed.
++ Block should be prioritised for GC */
++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc
++ failures on this block and tried to reuse it */
++ u32 has_summary:1; /* The block has a summary */
++
++ u32 has_shrink_hdr:1; /* This block has at least one shrink header */
++ u32 seq_number; /* block sequence number for yaffs2 */
++
++};
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++struct yaffs_obj_hdr {
++ enum yaffs_obj_type type;
++
++ /* Apply to everything */
++ int parent_obj_id;
++ u16 sum_no_longer_used; /* checksum of name. No longer used */
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ /* The following apply to all object types except for hard links */
++ u32 yst_mode; /* protection */
++
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++
++ /* File size applies to files only */
++ u32 file_size_low;
++
++ /* Equivalent object id applies to hard links only. */
++ int equiv_id;
++
++ /* Alias is for symlinks only. */
++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++ u32 yst_rdev; /* stuff for block and char devices (major/min) */
++
++ u32 win_ctime[2];
++ u32 win_atime[2];
++ u32 win_mtime[2];
++
++ u32 inband_shadowed_obj_id;
++ u32 inband_is_shrink;
++
++ u32 file_size_high;
++ u32 reserved[1];
++ int shadows_obj; /* This object header shadows the
++ specified object if > 0 */
++
++ /* is_shrink applies to object headers written when wemake a hole. */
++ u32 is_shrink;
++
++};
++
++/*--------------------------- Tnode -------------------------- */
++
++struct yaffs_tnode {
++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
++};
++
++/*------------------------ Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++struct yaffs_file_var {
++ loff_t file_size;
++ loff_t scanned_size;
++ loff_t shrink_size;
++ int top_level;
++ struct yaffs_tnode *top;
++};
++
++struct yaffs_dir_var {
++ struct list_head children; /* list of child links */
++ struct list_head dirty; /* Entry for list of dirty directories */
++};
++
++struct yaffs_symlink_var {
++ YCHAR *alias;
++};
++
++struct yaffs_hardlink_var {
++ struct yaffs_obj *equiv_obj;
++ u32 equiv_id;
++};
++
++union yaffs_obj_var {
++ struct yaffs_file_var file_variant;
++ struct yaffs_dir_var dir_variant;
++ struct yaffs_symlink_var symlink_variant;
++ struct yaffs_hardlink_var hardlink_variant;
++};
++
++struct yaffs_obj {
++ u8 deleted:1; /* This should only apply to unlinked files. */
++ u8 soft_del:1; /* it has also been soft deleted */
++ u8 unlinked:1; /* An unlinked file.*/
++ u8 fake:1; /* A fake object has no presence on NAND. */
++ u8 rename_allowed:1; /* Some objects cannot be renamed. */
++ u8 unlink_allowed:1;
++ u8 dirty:1; /* the object needs to be written to flash */
++ u8 valid:1; /* When the file system is being loaded up, this
++ * object might be created before the data
++ * is available
++ * ie. file data chunks encountered before
++ * the header.
++ */
++ u8 lazy_loaded:1; /* This object has been lazy loaded and
++ * is missing some detail */
++
++ u8 defered_free:1; /* Object is removed from NAND, but is
++ * still in the inode cache.
++ * Free of object is defered.
++ * until the inode is released.
++ */
++ u8 being_created:1; /* This object is still being created
++ * so skip some verification checks. */
++ u8 is_shadowed:1; /* This object is shadowed on the way
++ * to being renamed. */
++
++ u8 xattr_known:1; /* We know if this has object has xattribs
++ * or not. */
++ u8 has_xattr:1; /* This object has xattribs.
++ * Only valid if xattr_known. */
++
++ u8 serial; /* serial number of chunk in NAND.*/
++ u16 sum; /* sum of the name to speed searching */
++
++ struct yaffs_dev *my_dev; /* The device I'm on */
++
++ struct list_head hash_link; /* list of objects in hash bucket */
++
++ struct list_head hard_links; /* hard linked object chain*/
++
++ /* directory structure stuff */
++ /* also used for linking up the free list */
++ struct yaffs_obj *parent;
++ struct list_head siblings;
++
++ /* Where's my object header in NAND? */
++ int hdr_chunk;
++
++ int n_data_chunks; /* Number of data chunks for this file. */
++
++ u32 obj_id; /* the object id value */
++
++ u32 yst_mode;
++
++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
++
++#ifdef CONFIG_YAFFS_WINCE
++ u32 win_ctime[2];
++ u32 win_mtime[2];
++ u32 win_atime[2];
++#else
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++#endif
++
++ u32 yst_rdev;
++
++ void *my_inode;
++
++ enum yaffs_obj_type variant_type;
++
++ union yaffs_obj_var variant;
++
++};
++
++struct yaffs_obj_bucket {
++ struct list_head list;
++ int count;
++};
++
++/* yaffs_checkpt_obj holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++struct yaffs_checkpt_obj {
++ int struct_type;
++ u32 obj_id;
++ u32 parent_id;
++ int hdr_chunk;
++ enum yaffs_obj_type variant_type:3;
++ u8 deleted:1;
++ u8 soft_del:1;
++ u8 unlinked:1;
++ u8 fake:1;
++ u8 rename_allowed:1;
++ u8 unlink_allowed:1;
++ u8 serial;
++ int n_data_chunks;
++ loff_t size_or_equiv_obj;
++};
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few.
++ */
++
++struct yaffs_buffer {
++ u8 *buffer;
++ int in_use;
++};
++
++/*----------------- Device ---------------------------------*/
++
++struct yaffs_param {
++ const YCHAR *name;
++
++ /*
++ * Entry parameters set up way early. Yaffs sets up the rest.
++ * The structure should be zeroed out before use so that unused
++ * and default values are zero.
++ */
++
++ int inband_tags; /* Use unband tags */
++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
++ be a power of 2 */
++ int chunks_per_block; /* does not need to be a power of 2 */
++ int spare_bytes_per_chunk; /* spare area size */
++ int start_block; /* Start block we're allowed to use */
++ int end_block; /* End block we're allowed to use */
++ int n_reserved_blocks; /* Tuneable so that we can reduce
++ * reserved blocks on NOR and RAM. */
++
++ int n_caches; /* If <= 0, then short op caching is disabled,
++ * else the number of short op caches.
++ */
++ int cache_bypass_aligned; /* If non-zero then bypass the cache for
++ * aligned writes.
++ */
++
++ int use_nand_ecc; /* Flag to decide whether or not to use
++ * NAND driver ECC on data (yaffs1) */
++ int tags_9bytes; /* Use 9 byte tags */
++ int no_tags_ecc; /* Flag to decide whether or not to do ECC
++ * on packed tags (yaffs2) */
++
++ int is_yaffs2; /* Use yaffs2 mode on this device */
++
++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
++
++ int refresh_period; /* How often to check for a block refresh */
++
++ /* Checkpoint control. Can be set before or after initialisation */
++ u8 skip_checkpt_rd;
++ u8 skip_checkpt_wr;
++
++ int enable_xattr; /* Enable xattribs */
++
++ int max_objects; /*
++ * Set to limit the number of objects created.
++ * 0 = no limit.
++ */
++
++ /* The remove_obj_fn function must be supplied by OS flavours that
++ * need it.
++ * yaffs direct uses it to implement the faster readdir.
++ * Linux uses it to protect the directory during unlocking.
++ */
++ void (*remove_obj_fn) (struct yaffs_obj *obj);
++
++ /* Callback to mark the superblock dirty */
++ void (*sb_dirty_fn) (struct yaffs_dev *dev);
++
++ /* Callback to control garbage collection. */
++ unsigned (*gc_control_fn) (struct yaffs_dev *dev);
++
++ /* Debug control flags. Don't use unless you know what you're doing */
++ int use_header_file_size; /* Flag to determine if we should use
++ * file sizes from the header */
++ int disable_lazy_load; /* Disable lazy loading on this device */
++ int wide_tnodes_disabled; /* Set to disable wide tnodes */
++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of
++ * softdeletion. */
++
++ int defered_dir_update; /* Set to defer directory updates */
++
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ int auto_unicode;
++#endif
++ int always_check_erased; /* Force chunk erased check always on */
++
++ int disable_summary;
++ int disable_bad_block_marking;
++
++};
++
++struct yaffs_driver {
++ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len);
++ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result);
++ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_initialise_fn) (struct yaffs_dev *dev);
++ int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
++};
++
++struct yaffs_tags_handler {
++ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags);
++ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags);
++
++ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++};
++
++struct yaffs_dev {
++ struct yaffs_param param;
++ struct yaffs_driver drv;
++ struct yaffs_tags_handler tagger;
++
++ /* Context storage. Holds extra OS specific data for this device */
++
++ void *os_context;
++ void *driver_context;
++
++ struct list_head dev_list;
++
++ int ll_init;
++ /* Runtime parameters. Set up by YAFFS. */
++ int data_bytes_per_chunk;
++
++ /* Non-wide tnode stuff */
++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
++ * the tnodes are not wide enough.
++ */
++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
++
++ /* Stuff to support wide tnodes */
++ u32 tnode_width;
++ u32 tnode_mask;
++ u32 tnode_size;
++
++ /* Stuff for figuring out file offset to chunk conversions */
++ u32 chunk_shift; /* Shift value */
++ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
++ u32 chunk_mask; /* Mask to use for power-of-2 case */
++
++ int is_mounted;
++ int read_only;
++ int is_checkpointed;
++
++ /* Stuff to support block offsetting to support start block zero */
++ int internal_start_block;
++ int internal_end_block;
++ int block_offset;
++ int chunk_offset;
++
++ /* Runtime checkpointing stuff */
++ int checkpt_page_seq; /* running sequence number of checkpt pages */
++ int checkpt_byte_count;
++ int checkpt_byte_offs;
++ u8 *checkpt_buffer;
++ int checkpt_open_write;
++ int blocks_in_checkpt;
++ int checkpt_cur_chunk;
++ int checkpt_cur_block;
++ int checkpt_next_block;
++ int *checkpt_block_list;
++ int checkpt_max_blocks;
++ u32 checkpt_sum;
++ u32 checkpt_xor;
++
++ int checkpoint_blocks_required; /* Number of blocks needed to store
++ * current checkpoint set */
++
++ /* Block Info */
++ struct yaffs_block_info *block_info;
++ u8 *chunk_bits; /* bitmap of chunks in use */
++ u8 block_info_alt:1; /* allocated using alternative alloc */
++ u8 chunk_bits_alt:1; /* allocated using alternative alloc */
++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
++ * Must be consistent with chunks_per_block.
++ */
++
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int alloc_block_finder; /* Used to search for next allocation block */
++
++ /* Object and Tnode memory management */
++ void *allocator;
++ int n_obj;
++ int n_tnodes;
++
++ int n_hardlinks;
++
++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
++ u32 bucket_finder;
++
++ int n_free_chunks;
++
++ /* Garbage collection control */
++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
++ u32 n_clean_ups;
++
++ unsigned has_pending_prioritised_gc; /* We think this device might
++ have pending prioritised gcs */
++ unsigned gc_disable;
++ unsigned gc_block_finder;
++ unsigned gc_dirtiest;
++ unsigned gc_pages_in_use;
++ unsigned gc_not_done;
++ unsigned gc_block;
++ unsigned gc_chunk;
++ unsigned gc_skip;
++ struct yaffs_summary_tags *gc_sum_tags;
++
++ /* Special directories */
++ struct yaffs_obj *root_dir;
++ struct yaffs_obj *lost_n_found;
++
++ int buffered_block; /* Which block is buffered here? */
++ int doing_buffered_block_rewrite;
++
++ struct yaffs_cache *cache;
++ int cache_last_use;
++
++ /* Stuff for background deletion and unlinked files. */
++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
++ files live. */
++ struct yaffs_obj *del_dir; /* Directory where deleted objects are
++ sent to disappear. */
++ struct yaffs_obj *unlinked_deletion; /* Current file being
++ background deleted. */
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* Temporary buffer management */
++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
++ int max_temp;
++ int temp_in_use;
++ int unmanaged_buffer_allocs;
++ int unmanaged_buffer_deallocs;
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ allocating block */
++ unsigned oldest_dirty_seq;
++ unsigned oldest_dirty_block;
++
++ /* Block refreshing */
++ int refresh_skip; /* A skip down counter.
++ * Refresh happens when this gets to zero. */
++
++ /* Dirty directory handling */
++ struct list_head dirty_dirs; /* List of dirty directories */
++
++ /* Summary */
++ int chunks_per_summary;
++ struct yaffs_summary_tags *sum_tags;
++
++ /* Statistics */
++ u32 n_page_writes;
++ u32 n_page_reads;
++ u32 n_erasures;
++ u32 n_bad_queries;
++ u32 n_bad_markings;
++ u32 n_erase_failures;
++ u32 n_gc_copies;
++ u32 all_gcs;
++ u32 passive_gc_count;
++ u32 oldest_dirty_gc_count;
++ u32 n_gc_blocks;
++ u32 bg_gcs;
++ u32 n_retried_writes;
++ u32 n_retired_blocks;
++ u32 n_ecc_fixed;
++ u32 n_ecc_unfixed;
++ u32 n_tags_ecc_fixed;
++ u32 n_tags_ecc_unfixed;
++ u32 n_deletions;
++ u32 n_unmarked_deletions;
++ u32 refresh_count;
++ u32 cache_hits;
++ u32 tags_used;
++ u32 summary_used;
++
++};
++
++/* The CheckpointDevice structure holds the device information that changes
++ *at runtime and must be preserved over unmount/mount cycles.
++ */
++struct yaffs_checkpt_dev {
++ int struct_type;
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int n_free_chunks;
++
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ * allocating block */
++
++};
++
++struct yaffs_checkpt_validity {
++ int struct_type;
++ u32 magic;
++ u32 version;
++ u32 head;
++};
++
++struct yaffs_shadow_fixer {
++ int obj_id;
++ int shadowed_id;
++ struct yaffs_shadow_fixer *next;
++};
++
++/* Structure for doing xattr modifications */
++struct yaffs_xattr_mod {
++ int set; /* If 0 then this is a deletion */
++ const YCHAR *name;
++ const void *data;
++ int size;
++ int flags;
++ int result;
++};
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_guts_initialise(struct yaffs_dev *dev);
++void yaffs_deinitialise(struct yaffs_dev *dev);
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++ struct yaffs_obj *new_dir, const YCHAR * new_name);
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
++int yaffs_del_obj(struct yaffs_obj *obj);
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type);
++
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
++int yaffs_get_obj_inode(struct yaffs_obj *obj);
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
++int yaffs_get_obj_link_count(struct yaffs_obj *obj);
++
++/* File operations */
++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
++ int n_bytes);
++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid);
++
++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
++
++/* Flushing and checkpointing */
++void yaffs_flush_whole_cache(struct yaffs_dev *dev);
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev);
++int yaffs_checkpoint_restore(struct yaffs_dev *dev);
++
++/* Directory operations */
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid);
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
++ const YCHAR *name);
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
++
++/* Link operations */
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
++ struct yaffs_obj *equiv_obj);
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
++
++/* Symlink operations */
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias);
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev);
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
++ const void *value, int size, int flags);
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
++ int size);
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
++
++/* Special directories */
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj);
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
++
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
++
++/* Debug dump */
++int yaffs_dump_obj(struct yaffs_obj *obj);
++
++void yaffs_guts_test(struct yaffs_dev *dev);
++int yaffs_guts_ll_init(struct yaffs_dev *dev);
++
++
++/* A few useful functions to be used within the core files*/
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn);
++int yaffs_check_ff(u8 *buffer, int n_bytes);
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type);
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan);
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh);
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
++YCHAR *yaffs_clone_str(const YCHAR *str);
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
++ int force, int is_shrink, int shadows,
++ struct yaffs_xattr_mod *xop);
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning);
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn);
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id);
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos);
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev);
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out);
++/*
++ * Marshalling functions to get loff_t file sizes into aand out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
++loff_t yaffs_max_file_size(struct yaffs_dev *dev);
++
++/*
++ * Debug function to count number of blocks in each state
++ * NB Needs to be called with correct number of integers
++ */
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_linux.h linux-3.13.11/fs/yaffs2/yaffs_linux.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_linux.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_LINUX_H__
++#define __YAFFS_LINUX_H__
++
++#include "yportenv.h"
++
++struct yaffs_linux_context {
++ struct list_head context_list; /* List of these we have mounted */
++ struct yaffs_dev *dev;
++ struct super_block *super;
++ struct task_struct *bg_thread; /* Background thread for this device */
++ int bg_running;
++ struct mutex gross_lock; /* Gross locking mutex*/
++ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
++ * at compile time so we have to allocate it.
++ */
++ struct list_head search_contexts;
++ struct task_struct *readdir_process;
++ unsigned mount_id;
++ int dirty;
++};
++
++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
++
++#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
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_mtdif.c linux-3.13.11/fs/yaffs2/yaffs_mtdif.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_mtdif.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,309 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/major.h"
++#include "linux/mtd/nand.h"
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_linux.h"
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++#define mtd_erase(m, ei) (m)->erase(m, ei)
++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
++#endif
++
++
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ u32 addr =
++ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ struct erase_info ei;
++ int retval = 0;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++
++static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
++ dev, nand_chunk, data, data_len, oob, oob_len);
++
++ if (!data || !data_len) {
++ data = NULL;
++ data_len = 0;
++ }
++
++ if (!oob || !oob_len) {
++ oob = NULL;
++ oob_len = 0;
++ }
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = (u8 *)data;
++ ops.oobbuf = (u8 *)oob;
++
++ retval = mtd_write_oob(mtd, addr, &ops);
++ if (retval) {
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "write_oob failed, chunk %d, mtd error %d",
++ nand_chunk, retval);
++ }
++ return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = data;
++ ops.oobbuf = oob;
++
++#if (MTD_VERSION_CODE < MTD_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",
++ nand_chunk, retval);
++
++ switch (retval) {
++ case 0:
++ /* no error */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++
++ case -EUCLEAN:
++ /* MTD's ECC fixed the data */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ break;
++
++ case -EBADMSG:
++ default:
++ /* MTD's ECC could not fix the data */
++ dev->n_ecc_unfixed++;
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ loff_t addr;
++ struct erase_info ei;
++ int retval = 0;
++ u32 block_size;
++
++ block_size = dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ addr = ((loff_t) block_no) * block_size;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = block_size;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
++
++ retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
++
++ retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_initialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++
++ drv->drv_write_chunk_fn = yaffs_mtd_write;
++ drv->drv_read_chunk_fn = yaffs_mtd_read;
++ drv->drv_erase_fn = yaffs_mtd_erase;
++ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
++ drv->drv_check_bad_fn = yaffs_mtd_check_bad;
++ drv->drv_initialise_fn = yaffs_mtd_initialise;
++ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
++}
++
++
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
++{
++ struct mtd_info *mtd;
++
++ mtd = yaffs_get_mtd_device(sdev);
++
++ /* Check it's an mtd device..... */
++ if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
++ return NULL; /* This isn't an mtd device */
++
++ /* Check it's NAND */
++ if (mtd->type != MTD_NANDFLASH) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device is not NAND it's type %d",
++ mtd->type);
++ return NULL;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
++ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
++ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++ yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
++#else
++ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
++#endif
++
++ return mtd;
++}
++
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++{
++ if (yaffs_version == 2) {
++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++ !inband_tags) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not have the right page sizes"
++ );
++ return -1;
++ }
++ } else {
++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not support have the right page sizes"
++ );
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++
++void yaffs_put_mtd_device(struct mtd_info *mtd)
++{
++ if(mtd)
++ put_mtd_device(mtd);
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_mtdif.h linux-3.13.11/fs/yaffs2/yaffs_mtdif.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_mtdif.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev);
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
++void yaffs_put_mtd_device(struct mtd_info *mtd);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_nameval.c linux-3.13.11/fs/yaffs2/yaffs_nameval.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_nameval.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This simple implementation of a name-value store assumes a small number of
++* values and fits into a small finite buffer.
++ *
++ * Each attribute is stored as a record:
++ * sizeof(int) bytes record size.
++ * strnlen+1 bytes name null terminated.
++ * nbytes value.
++ * ----------
++ * total size stored in record size
++ *
++ * This code has not been tested with unicode yet.
++ */
++
++#include "yaffs_nameval.h"
++
++#include "yportenv.h"
++
++static int nval_find(const char *xb, int xb_size, const YCHAR *name,
++ int *exist_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
++ name, size)) {
++ if (exist_size)
++ *exist_size = size;
++ return pos;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ if (exist_size)
++ *exist_size = 0;
++ return -ENODATA;
++}
++
++static int nval_used(const char *xb, int xb_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return pos;
++}
++
++int nval_del(char *xb, int xb_size, const YCHAR *name)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos < 0 || pos >= xb_size)
++ return -ENODATA;
++
++ /* Find size, shift rest over this record,
++ * then zero out the rest of buffer */
++ memcpy(&size, xb + pos, sizeof(int));
++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
++ memset(xb + (xb_size - size), 0, size);
++ return 0;
++}
++
++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
++ int bsize, int flags)
++{
++ int pos;
++ int namelen = strnlen(name, xb_size);
++ int reclen;
++ int size_exist = 0;
++ int space;
++ int start;
++
++ pos = nval_find(xb, xb_size, name, &size_exist);
++
++ if (flags & XATTR_CREATE && pos >= 0)
++ return -EEXIST;
++ if (flags & XATTR_REPLACE && pos < 0)
++ return -ENODATA;
++
++ start = nval_used(xb, xb_size);
++ space = xb_size - start + size_exist;
++
++ reclen = (sizeof(int) + namelen + 1 + bsize);
++
++ if (reclen > space)
++ return -ENOSPC;
++
++ if (pos >= 0) {
++ nval_del(xb, xb_size, name);
++ start = nval_used(xb, xb_size);
++ }
++
++ pos = start;
++
++ memcpy(xb + pos, &reclen, sizeof(int));
++ pos += sizeof(int);
++ strncpy((YCHAR *) (xb + pos), name, reclen);
++ pos += (namelen + 1);
++ memcpy(xb + pos, buf, bsize);
++ return 0;
++}
++
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos >= 0 && pos < xb_size) {
++
++ memcpy(&size, xb + pos, sizeof(int));
++ pos += sizeof(int); /* advance past record length */
++ size -= sizeof(int);
++
++ /* Advance over name string */
++ while (xb[pos] && size > 0 && pos < xb_size) {
++ pos++;
++ size--;
++ }
++ /*Advance over NUL */
++ pos++;
++ size--;
++
++ /* If bsize is zero then this is a size query.
++ * Return the size, but don't copy.
++ */
++ if (!bsize)
++ return size;
++
++ if (size <= bsize) {
++ memcpy(buf, xb + pos, size);
++ return size;
++ }
++ }
++ if (pos >= 0)
++ return -ERANGE;
++
++ return -ENODATA;
++}
++
++int nval_list(const char *xb, int xb_size, char *buf, int bsize)
++{
++ int pos = 0;
++ int size;
++ int name_len;
++ int ncopied = 0;
++ int filled = 0;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > sizeof(int) &&
++ size <= xb_size &&
++ (pos + size) < xb_size &&
++ !filled) {
++ pos += sizeof(int);
++ size -= sizeof(int);
++ name_len = strnlen((YCHAR *) (xb + pos), size);
++ if (ncopied + name_len + 1 < bsize) {
++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
++ buf += name_len;
++ *buf = '\0';
++ buf++;
++ if (sizeof(YCHAR) > 1) {
++ *buf = '\0';
++ buf++;
++ }
++ ncopied += (name_len + 1);
++ } else {
++ filled = 1;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return ncopied;
++}
++
++int nval_hasvalues(const char *xb, int xb_size)
++{
++ return nval_used(xb, xb_size) > 0;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_nameval.h linux-3.13.11/fs/yaffs2/yaffs_nameval.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_nameval.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __NAMEVAL_H__
++#define __NAMEVAL_H__
++
++#include "yportenv.h"
++
++int nval_del(char *xb, int xb_size, const YCHAR * name);
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++ int bsize, int flags);
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize);
++int nval_list(const char *xb, int xb_size, char *buf, int bsize);
++int nval_hasvalues(const char *xb, int xb_size);
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_nand.c linux-3.13.11/fs/yaffs2/yaffs_nand.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_nand.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,122 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++
++#include "yaffs_getblockinfo.h"
++#include "yaffs_summary.h"
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ struct yaffs_ext_tags local_tags;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_reads++;
++
++ /* If there are no tags provided use local tags. */
++ if (!tags)
++ tags = &local_tags;
++
++ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
++
++ struct yaffs_block_info *bi;
++ bi = yaffs_get_block_info(dev,
++ nand_chunk /
++ dev->param.chunks_per_block);
++ yaffs_handle_chunk_error(dev, bi);
++ }
++ return result;
++}
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_writes++;
++
++ if (!tags) {
++ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ tags->seq_number = dev->seq_number;
++ tags->chunk_used = 1;
++ yaffs_trace(YAFFS_TRACE_WRITE,
++ "Writing chunk %d tags %d %d",
++ nand_chunk, tags->obj_id, tags->chunk_id);
++
++ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
++ buffer, tags);
++
++ yaffs_summary_add(dev, tags, nand_chunk);
++
++ return result;
++}
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ block_no -= dev->block_offset;
++ dev->n_bad_markings++;
++
++ if (dev->param.disable_bad_block_marking)
++ return YAFFS_OK;
++
++ return dev->tagger.mark_bad_fn(dev, block_no);
++}
++
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ block_no -= dev->block_offset;
++ return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
++}
++
++int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ int result;
++
++ block_no -= dev->block_offset;
++ dev->n_erasures++;
++ result = dev->drv.drv_erase_fn(dev, block_no);
++ return result;
++}
++
++int yaffs_init_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_initialise_fn)
++ return dev->drv.drv_initialise_fn(dev);
++ return YAFFS_OK;
++}
++
++int yaffs_deinit_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_deinitialise_fn)
++ return dev->drv.drv_deinitialise_fn(dev);
++ return YAFFS_OK;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_nand.h linux-3.13.11/fs/yaffs2/yaffs_nand.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_nand.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ unsigned *seq_number);
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
++
++int yaffs_init_nand(struct yaffs_dev *dev);
++int yaffs_deinit_nand(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.13.11/fs/yaffs2/yaffs_packedtags1.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_packedtags1.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++static const u8 all_ff[20] = {
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t)
++{
++ pt->chunk_id = t->chunk_id;
++ pt->serial_number = t->serial_number;
++ pt->n_bytes = t->n_bytes;
++ pt->obj_id = t->obj_id;
++ pt->ecc = 0;
++ pt->deleted = (t->is_deleted) ? 0 : 1;
++ pt->unused_stuff = 0;
++ pt->should_be_ff = 0xffffffff;
++}
++
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt)
++{
++
++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
++ t->block_bad = 0;
++ if (pt->should_be_ff != 0xffffffff)
++ t->block_bad = 1;
++ t->chunk_used = 1;
++ t->obj_id = pt->obj_id;
++ t->chunk_id = pt->chunk_id;
++ t->n_bytes = pt->n_bytes;
++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ t->is_deleted = (pt->deleted) ? 0 : 1;
++ t->serial_number = pt->serial_number;
++ } else {
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++ }
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.13.11/fs/yaffs2/yaffs_packedtags1.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_packedtags1.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++struct yaffs_packed_tags1 {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 deleted:1;
++ u32 unused_stuff:1;
++ unsigned should_be_ff;
++
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt);
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.13.11/fs/yaffs2/yaffs_packedtags2.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_packedtags2.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunk_id */
++
++#define EXTRA_HEADER_INFO_FLAG 0x80000000
++#define EXTRA_SHRINK_FLAG 0x40000000
++#define EXTRA_SHADOWS_FLAG 0x20000000
++#define EXTRA_SPARE_FLAGS 0x10000000
++
++#define ALL_EXTRA_FLAGS 0xf0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
++
++static void yaffs_dump_packed_tags2_tags_only(
++ const struct yaffs_packed_tags2_tags_only *ptt)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "packed tags obj %d chunk %d byte %d seq %d",
++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
++}
++
++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
++{
++ yaffs_dump_packed_tags2_tags_only(&pt->t);
++}
++
++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
++ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
++ t->seq_number);
++
++}
++
++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
++{
++ if (t->chunk_id != 0 || !t->extra_available)
++ return 0;
++
++ /* Check if the file size is too long to store */
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
++ (t->extra_file_size >> 31) != 0)
++ return 0;
++ return 1;
++}
++
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
++ const struct yaffs_ext_tags *t)
++{
++ ptt->chunk_id = t->chunk_id;
++ ptt->seq_number = t->seq_number;
++ ptt->n_bytes = t->n_bytes;
++ ptt->obj_id = t->obj_id;
++
++ /* Only store extra tags for object headers.
++ * If it is a file then only store if the file size is short\
++ * enough to fit.
++ */
++ if (yaffs_check_tags_extra_packable(t)) {
++ /* Store the extra header info instead */
++ /* We save the parent object in the chunk_id */
++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
++ if (t->extra_is_shrink)
++ ptt->chunk_id |= EXTRA_SHRINK_FLAG;
++ if (t->extra_shadows)
++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
++
++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ ptt->n_bytes = t->extra_equiv_id;
++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ ptt->n_bytes = (unsigned) t->extra_file_size;
++ else
++ ptt->n_bytes = 0;
++ }
++
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc)
++{
++ yaffs_pack_tags2_tags_only(&pt->t, t);
++
++ if (tags_ecc)
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc);
++}
++
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *ptt)
++{
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++
++ if (ptt->seq_number == 0xffffffff)
++ return;
++
++ t->block_bad = 0;
++ t->chunk_used = 1;
++ t->obj_id = ptt->obj_id;
++ t->chunk_id = ptt->chunk_id;
++ t->n_bytes = ptt->n_bytes;
++ t->is_deleted = 0;
++ t->serial_number = 0;
++ t->seq_number = ptt->seq_number;
++
++ /* Do extra header info stuff */
++ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
++ t->chunk_id = 0;
++ t->n_bytes = 0;
++
++ t->extra_available = 1;
++ t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
++ t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
++ t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
++ t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ t->extra_equiv_id = ptt->n_bytes;
++ else
++ t->extra_file_size = ptt->n_bytes;
++ }
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc)
++{
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ if (pt->t.seq_number != 0xffffffff && tags_ecc) {
++ /* Chunk is in use and we need to do ECC */
++
++ struct yaffs_ecc_other ecc;
++ int result;
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &ecc);
++ result =
++ yaffs_ecc_correct_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc, &ecc);
++ switch (result) {
++ case 0:
++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++ case 1:
++ ecc_result = YAFFS_ECC_RESULT_FIXED;
++ break;
++ case -1:
++ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ break;
++ default:
++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ }
++ }
++ yaffs_unpack_tags2_tags_only(t, &pt->t);
++
++ t->ecc_result = ecc_result;
++
++ yaffs_dump_packed_tags2(pt);
++ yaffs_dump_tags2(t);
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.13.11/fs/yaffs2/yaffs_packedtags2.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_packedtags2.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++struct yaffs_packed_tags2_tags_only {
++ unsigned seq_number;
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++struct yaffs_packed_tags2 {
++ struct yaffs_packed_tags2_tags_only t;
++ struct yaffs_ecc_other ecc;
++};
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc);
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *pt);
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_summary.c linux-3.13.11/fs/yaffs2/yaffs_summary.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_summary.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_summary.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,312 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Summaries write the useful part of the tags for the chunks in a block into an
++ * an array which is written to the last n chunks of the block.
++ * Reading the summaries gives all the tags for the block in one read. Much
++ * faster.
++ *
++ * Chunks holding summaries are marked with tags making it look like
++ * they are part of a fake file.
++ *
++ * The summary could also be used during gc.
++ *
++ */
++
++#include "yaffs_summary.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_bitmap.h"
++
++/*
++ * The summary is built up in an array of summary tags.
++ * This gets written to the last one or two (maybe more) chunks in a block.
++ * A summary header is written as the first part of each chunk of summary data.
++ * The summary header must match or the summary is rejected.
++ */
++
++/* Summary tags don't need the sequence number because that is redundant. */
++struct yaffs_summary_tags {
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++/* Summary header */
++struct yaffs_summary_header {
++ unsigned version; /* Must match current version */
++ unsigned block; /* Must be this block */
++ unsigned seq; /* Must be this sequence number */
++ unsigned sum; /* Just add up all the bytes in the tags */
++};
++
++
++static void yaffs_summary_clear(struct yaffs_dev *dev)
++{
++ if (!dev->sum_tags)
++ return;
++ memset(dev->sum_tags, 0, dev->chunks_per_summary *
++ sizeof(struct yaffs_summary_tags));
++}
++
++
++void yaffs_summary_deinit(struct yaffs_dev *dev)
++{
++ kfree(dev->sum_tags);
++ dev->sum_tags = NULL;
++ kfree(dev->gc_sum_tags);
++ dev->gc_sum_tags = NULL;
++ dev->chunks_per_summary = 0;
++}
++
++int yaffs_summary_init(struct yaffs_dev *dev)
++{
++ int sum_bytes;
++ int chunks_used; /* Number of chunks used by summary */
++ int sum_tags_bytes;
++
++ sum_bytes = dev->param.chunks_per_block *
++ sizeof(struct yaffs_summary_tags);
++
++ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
++ (dev->data_bytes_per_chunk -
++ sizeof(struct yaffs_summary_header));
++
++ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ if (!dev->sum_tags || !dev->gc_sum_tags) {
++ yaffs_summary_deinit(dev);
++ return YAFFS_FAIL;
++ }
++
++ yaffs_summary_clear(dev);
++
++ return YAFFS_OK;
++}
++
++static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
++{
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int i;
++ unsigned sum = 0;
++
++ i = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ while (i > 0) {
++ sum += *sum_buffer;
++ sum_buffer++;
++ i--;
++ }
++
++ return sum;
++}
++
++static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int n_bytes;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ memset(&tags, 0, sizeof(struct yaffs_ext_tags));
++ tags.obj_id = YAFFS_OBJECTID_SUMMARY;
++ tags.chunk_id = 1;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ hdr.version = YAFFS_SUMMARY_VERSION;
++ hdr.block = blk;
++ hdr.seq = bi->seq_number;
++ hdr.sum = yaffs_summary_sum(dev);
++
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ memcpy(buffer, &hdr, sizeof(hdr));
++ memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
++ tags.n_bytes = this_tx + sizeof(hdr);
++ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (result != YAFFS_OK)
++ break;
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ dev->n_free_chunks--;
++
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ tags.chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++
++ if (result == YAFFS_OK)
++ bi->has_summary = 1;
++
++
++ return result;
++}
++
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)st;
++ int n_bytes;
++ int chunk_id;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ int sum_tags_bytes;
++
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = blk * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ chunk_id = 1;
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (tags.chunk_id != chunk_id ||
++ tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
++ tags.chunk_used == 0 ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.n_bytes != (this_tx + sizeof(hdr)))
++ result = YAFFS_FAIL;
++ if (result != YAFFS_OK)
++ break;
++
++ if (st == dev->sum_tags) {
++ /* If we're scanning then update the block info */
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ }
++ memcpy(&hdr, buffer, sizeof(hdr));
++ memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (result == YAFFS_OK) {
++ /* Verify header */
++ if (hdr.version != YAFFS_SUMMARY_VERSION ||
++ hdr.seq != bi->seq_number ||
++ hdr.sum != yaffs_summary_sum(dev))
++ result = YAFFS_FAIL;
++ }
++
++ if (st == dev->sum_tags && result == YAFFS_OK)
++ bi->has_summary = 1;
++
++ return result;
++}
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_nand)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
++ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
++
++ if (!dev->sum_tags)
++ return YAFFS_OK;
++
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ yaffs_pack_tags2_tags_only(&tags_only, tags);
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ sum_tags->chunk_id = tags_only.chunk_id;
++ sum_tags->n_bytes = tags_only.n_bytes;
++ sum_tags->obj_id = tags_only.obj_id;
++
++ if (chunk_in_block == dev->chunks_per_summary - 1) {
++ /* Time to write out the summary */
++ yaffs_summary_write(dev, block_in_nand);
++ yaffs_summary_clear(dev);
++ yaffs_skip_rest_of_block(dev);
++ }
++ }
++ return YAFFS_OK;
++}
++
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ tags_only.chunk_id = sum_tags->chunk_id;
++ tags_only.n_bytes = sum_tags->n_bytes;
++ tags_only.obj_id = sum_tags->obj_id;
++ yaffs_unpack_tags2_tags_only(tags, &tags_only);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int i;
++
++ if (!bi->has_summary)
++ return;
++
++ for (i = dev->chunks_per_summary;
++ i < dev->param.chunks_per_block;
++ i++) {
++ if (yaffs_check_chunk_bit(dev, blk, i)) {
++ yaffs_clear_chunk_bit(dev, blk, i);
++ bi->pages_in_use--;
++ dev->n_free_chunks++;
++ }
++ }
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_summary.h linux-3.13.11/fs/yaffs2/yaffs_summary.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_summary.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_summary.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_SUMMARY_H__
++#define __YAFFS_SUMMARY_H__
++
++#include "yaffs_packedtags2.h"
++
++
++int yaffs_summary_init(struct yaffs_dev *dev);
++void yaffs_summary_deinit(struct yaffs_dev *dev);
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk);
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
++
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.13.11/fs/yaffs2/yaffs_tagscompat.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_tagscompat.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,381 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++
++
++/********** Tags ECC calculations *********/
++
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
++{
++ /* Calculate an ecc */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++ unsigned i, j;
++ unsigned ecc = 0;
++ unsigned bit = 0;
++
++ tags->ecc = 0;
++
++ for (i = 0; i < 8; i++) {
++ for (j = 1; j & 0xff; j <<= 1) {
++ bit++;
++ if (b[i] & j)
++ ecc ^= bit;
++ }
++ }
++ tags->ecc = ecc;
++}
++
++int yaffs_check_tags_ecc(struct yaffs_tags *tags)
++{
++ unsigned ecc = tags->ecc;
++
++ yaffs_calc_tags_ecc(tags);
++
++ ecc ^= tags->ecc;
++
++ if (ecc && ecc <= 64) {
++ /* TODO: Handle the failure better. Retire? */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++
++ ecc--;
++
++ b[ecc / 8] ^= (1 << (ecc & 7));
++
++ /* Now recvalc the ecc */
++ yaffs_calc_tags_ecc(tags);
++
++ return 1; /* recovered error */
++ } else if (ecc) {
++ /* Wierd ecc failure value */
++ /* TODO Need to do somethiong here */
++ return -1; /* unrecovered error */
++ }
++ return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++
++ yaffs_calc_tags_ecc(tags_ptr);
++
++ spare_ptr->tb0 = tu->as_bytes[0];
++ spare_ptr->tb1 = tu->as_bytes[1];
++ spare_ptr->tb2 = tu->as_bytes[2];
++ spare_ptr->tb3 = tu->as_bytes[3];
++ spare_ptr->tb4 = tu->as_bytes[4];
++ spare_ptr->tb5 = tu->as_bytes[5];
++ spare_ptr->tb6 = tu->as_bytes[6];
++ spare_ptr->tb7 = tu->as_bytes[7];
++}
++
++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
++ struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++ int result;
++
++ tu->as_bytes[0] = spare_ptr->tb0;
++ tu->as_bytes[1] = spare_ptr->tb1;
++ tu->as_bytes[2] = spare_ptr->tb2;
++ tu->as_bytes[3] = spare_ptr->tb3;
++ tu->as_bytes[4] = spare_ptr->tb4;
++ tu->as_bytes[5] = spare_ptr->tb5;
++ tu->as_bytes[6] = spare_ptr->tb6;
++ tu->as_bytes[7] = spare_ptr->tb7;
++
++ result = yaffs_check_tags_ecc(tags_ptr);
++ if (result > 0)
++ dev->n_tags_ecc_fixed++;
++ else if (result < 0)
++ dev->n_tags_ecc_unfixed++;
++}
++
++static void yaffs_spare_init(struct yaffs_spare *spare)
++{
++ memset(spare, 0xff, sizeof(struct yaffs_spare));
++}
++
++static int yaffs_wr_nand(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ struct yaffs_spare *spare)
++{
++ int data_size = dev->data_bytes_per_chunk;
++
++ return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, sizeof(*spare));
++}
++
++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data,
++ struct yaffs_spare *spare,
++ enum yaffs_ecc_result *ecc_result,
++ int correct_errors)
++{
++ int ret_val;
++ struct yaffs_spare local_spare;
++ int data_size;
++ int spare_size;
++ int ecc_result1, ecc_result2;
++ u8 calc_ecc[3];
++
++ if (!spare) {
++ /* If we don't have a real spare, then we use a local one. */
++ /* Need this for the calculation of the ecc */
++ spare = &local_spare;
++ }
++ data_size = dev->data_bytes_per_chunk;
++ spare_size = sizeof(struct yaffs_spare);
++
++ if (dev->param.use_nand_ecc)
++ return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, spare_size,
++ ecc_result);
++
++
++ /* Handle the ECC at this level. */
++
++ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *)spare, spare_size,
++ NULL);
++ if (!data || !correct_errors)
++ return ret_val;
++
++ /* Do ECC correction if needed. */
++ yaffs_ecc_calc(data, calc_ecc);
++ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
++ yaffs_ecc_calc(&data[256], calc_ecc);
++ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
++
++ if (ecc_result1 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result1 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result2 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result2 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result1 || ecc_result2) {
++ /* We had a data problem on this page */
++ yaffs_handle_rd_data_error(dev, nand_chunk);
++ }
++
++ if (ecc_result1 < 0 || ecc_result2 < 0)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ else if (ecc_result1 > 0 || ecc_result2 > 0)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ else
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ return ret_val;
++}
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++
++ /* Mark the block for retirement */
++ yaffs_get_block_info(dev, flash_block + dev->block_offset)->
++ needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>>Block %d marked for retirement",
++ flash_block);
++
++ /* TODO:
++ * Just do a garbage collection on the affected block
++ * then retire the block
++ * NB recursion
++ */
++}
++
++static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++
++ yaffs_spare_init(&spare);
++
++ if (ext_tags->is_deleted)
++ spare.page_status = 0;
++ else {
++ tags.obj_id = ext_tags->obj_id;
++ tags.chunk_id = ext_tags->chunk_id;
++
++ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
++ else
++ tags.n_bytes_msb = 3;
++
++ tags.serial_number = ext_tags->serial_number;
++
++ if (!dev->param.use_nand_ecc && data) {
++ yaffs_ecc_calc(data, spare.ecc1);
++ yaffs_ecc_calc(&data[256], spare.ecc2);
++ }
++
++ yaffs_load_tags_to_spare(&spare, &tags);
++ }
++ return yaffs_wr_nand(dev, nand_chunk, data, &spare);
++}
++
++static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ int deleted;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ if (!yaffs_rd_chunk_nand(dev, nand_chunk,
++ data, &spare, &ecc_result, 1))
++ return YAFFS_FAIL;
++
++ /* ext_tags may be NULL */
++ if (!ext_tags)
++ return YAFFS_OK;
++
++ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
++
++ ext_tags->is_deleted = deleted;
++ ext_tags->ecc_result = ecc_result;
++ ext_tags->block_bad = 0; /* We're reading it */
++ /* therefore it is not a bad block */
++ ext_tags->chunk_used =
++ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
++
++ if (ext_tags->chunk_used) {
++ yaffs_get_tags_from_spare(dev, &spare, &tags);
++ ext_tags->obj_id = tags.obj_id;
++ ext_tags->chunk_id = tags.chunk_id;
++ ext_tags->n_bytes = tags.n_bytes_lsb;
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ ext_tags->n_bytes |=
++ (((unsigned)tags.n_bytes_msb) << 10);
++
++ ext_tags->serial_number = tags.serial_number;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_spare spare;
++
++ memset(&spare, 0xff, sizeof(struct yaffs_spare));
++
++ spare.block_status = 'Y';
++
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
++ &spare);
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
++ NULL, &spare);
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ struct yaffs_spare spare0, spare1;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ enum yaffs_ecc_result dummy;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ *seq_number = 0;
++
++ /* Look for bad block markers in the first two chunks */
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
++ NULL, &spare0, &dummy, 0);
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
++ NULL, &spare1, &dummy, 0);
++
++ if (hweight8(spare0.block_status & spare1.block_status) < 7)
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ else
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++
++ return YAFFS_OK;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++ if(dev->param.is_yaffs2)
++ return;
++ if(!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
++ if(!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
++ if(!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++ if(!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.13.11/fs/yaffs2/yaffs_tagscompat.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_tagscompat.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++
++#include "yaffs_guts.h"
++
++#if 0
++
++
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++
++#endif
++
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev);
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
++int yaffs_check_tags_ecc(struct yaffs_tags *tags);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.13.11/fs/yaffs2/yaffs_tagsmarshall.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_tagsmarshall.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,199 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_packedtags2.h"
++
++static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ struct yaffs_packed_tags2 pt;
++ int retval;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_write chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ /* For yaffs2 writing there must be both data and tags.
++ * If we're using inband tags, then the tags are stuffed into
++ * the end of the data buffer.
++ */
++ if (!data || !tags)
++ BUG();
++ else if (dev->param.inband_tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)(data +
++ dev->
++ data_bytes_per_chunk);
++ yaffs_pack_tags2_tags_only(pt2tp, tags);
++ } else {
++ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
++ }
++
++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ (dev->param.inband_tags) ? NULL : packed_tags_ptr,
++ (dev->param.inband_tags) ? 0 : packed_tags_size);
++
++ return retval;
++}
++
++static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = 0;
++ int local_data = 0;
++ u8 spare_buffer[100];
++ enum yaffs_ecc_result ecc_result;
++
++ struct yaffs_packed_tags2 pt;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_read chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ if (dev->param.inband_tags) {
++ if (!data) {
++ local_data = 1;
++ data = yaffs_get_temp_buffer(dev);
++ }
++ }
++
++ if (dev->param.inband_tags || (data && !tags))
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ NULL, 0,
++ &ecc_result);
++ else if (tags)
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ spare_buffer, packed_tags_size,
++ &ecc_result);
++ else
++ BUG();
++
++
++ if (dev->param.inband_tags) {
++ if (tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)
++ &data[dev->data_bytes_per_chunk];
++ yaffs_unpack_tags2_tags_only(tags, pt2tp);
++ }
++ } else if (tags) {
++ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
++ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
++ }
++
++ if (local_data)
++ yaffs_release_temp_buffer(dev, data);
++
++ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ dev->n_ecc_unfixed++;
++ }
++
++ if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
++ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ }
++
++ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
++ block_no);
++
++ retval = dev->drv.drv_check_bad_fn(dev, block_no);
++
++ if (retval== YAFFS_FAIL) {
++ yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
++
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ *seq_number = 0;
++ } else {
++ struct yaffs_ext_tags t;
++
++ yaffs_tags_marshall_read(dev,
++ block_no * dev->param.chunks_per_block,
++ NULL, &t);
++
++ if (t.chunk_used) {
++ *seq_number = t.seq_number;
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++ } else {
++ *seq_number = 0;
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "block query returns seq %d state %d",
++ *seq_number, *state);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ return dev->drv.drv_mark_bad_fn(dev, block_no);
++
++}
++
++
++void yaffs_tags_marshall_install(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
++
++ if (!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
++
++ if (!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
++
++ if (!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
++
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.13.11/fs/yaffs2/yaffs_tagsmarshall.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_tagsmarshall.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSMARSHALL_H__
++#define __YAFFS_TAGSMARSHALL_H__
++
++#include "yaffs_guts.h"
++void yaffs_tags_marshall_install(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_trace.h linux-3.13.11/fs/yaffs2/yaffs_trace.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_trace.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_trace_mask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS 0x00000002
++#define YAFFS_TRACE_ALLOCATE 0x00000004
++#define YAFFS_TRACE_SCAN 0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
++#define YAFFS_TRACE_ERASE 0x00000020
++#define YAFFS_TRACE_GC 0x00000040
++#define YAFFS_TRACE_WRITE 0x00000080
++#define YAFFS_TRACE_TRACING 0x00000100
++#define YAFFS_TRACE_DELETION 0x00000200
++#define YAFFS_TRACE_BUFFERS 0x00000400
++#define YAFFS_TRACE_NANDACCESS 0x00000800
++#define YAFFS_TRACE_GC_DETAIL 0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
++#define YAFFS_TRACE_MTD 0x00004000
++#define YAFFS_TRACE_CHECKPOINT 0x00008000
++
++#define YAFFS_TRACE_VERIFY 0x00010000
++#define YAFFS_TRACE_VERIFY_NAND 0x00020000
++#define YAFFS_TRACE_VERIFY_FULL 0x00040000
++#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
++
++#define YAFFS_TRACE_SYNC 0x00100000
++#define YAFFS_TRACE_BACKGROUND 0x00200000
++#define YAFFS_TRACE_LOCK 0x00400000
++#define YAFFS_TRACE_MOUNT 0x00800000
++
++#define YAFFS_TRACE_ERROR 0x40000000
++#define YAFFS_TRACE_BUG 0x80000000
++#define YAFFS_TRACE_ALWAYS 0xf0000000
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_verify.c linux-3.13.11/fs/yaffs2/yaffs_verify.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_verify.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,529 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_verify.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++
++int yaffs_skip_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask &
++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_full_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char * const block_state_name[] = {
++ "Unknown",
++ "Needs scan",
++ "Scanning",
++ "Empty",
++ "Allocating",
++ "Full",
++ "Dirty",
++ "Checkpoint",
++ "Collecting",
++ "Dead"
++};
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
++{
++ int actually_used;
++ int in_use;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Report illegal runtime states */
++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has undefined state %d",
++ n, bi->block_state);
++
++ switch (bi->block_state) {
++ case YAFFS_BLOCK_STATE_UNKNOWN:
++ case YAFFS_BLOCK_STATE_SCANNING:
++ case YAFFS_BLOCK_STATE_NEEDS_SCAN:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has bad run-state %s",
++ n, block_state_name[bi->block_state]);
++ }
++
++ /* Check pages in use and soft deletions are legal */
++
++ actually_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->pages_in_use < 0 ||
++ bi->pages_in_use > dev->param.chunks_per_block ||
++ bi->soft_del_pages < 0 ||
++ bi->soft_del_pages > dev->param.chunks_per_block ||
++ actually_used < 0 || actually_used > dev->param.chunks_per_block)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has illegal values pages_in_used %d soft_del_pages %d",
++ n, bi->pages_in_use, bi->soft_del_pages);
++
++ /* Check chunk bitmap legal */
++ in_use = yaffs_count_chunk_bits(dev, n);
++ if (in_use != bi->pages_in_use)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
++ n, bi->pages_in_use, in_use);
++}
++
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n)
++{
++ yaffs_verify_blk(dev, bi, n);
++
++ /* After collection the block should be in the erased state */
++
++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Block %d is in state %d after gc, should be erased",
++ n, bi->block_state);
++ }
++}
++
++void yaffs_verify_blocks(struct yaffs_dev *dev)
++{
++ int i;
++ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
++ int illegal_states = 0;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ memset(state_count, 0, sizeof(state_count));
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ yaffs_verify_blk(dev, bi, i);
++
++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
++ state_count[bi->block_state]++;
++ else
++ illegal_states++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
++
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%d blocks have illegal states",
++ illegal_states);
++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many allocating blocks");
++
++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%s %d blocks",
++ block_state_name[i], state_count[i]);
++
++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Checkpoint block count wrong dev %d count %d",
++ dev->blocks_in_checkpt,
++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
++
++ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Erased block count wrong dev %d count %d",
++ dev->n_erased_blocks,
++ state_count[YAFFS_BLOCK_STATE_EMPTY]);
++
++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many collecting blocks %d (max is 1)",
++ state_count[YAFFS_BLOCK_STATE_COLLECTING]);
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in
++ * which case those tests will not be performed.
++ */
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!(tags && obj && oh)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Verifying object header tags %p obj %p oh %p",
++ tags, obj, oh);
++ return;
++ }
++
++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++ oh->type > YAFFS_OBJECT_TYPE_MAX)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header type is illegal value 0x%x",
++ tags->obj_id, oh->type);
++
++ if (tags->obj_id != obj->obj_id)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch obj_id %d",
++ tags->obj_id, obj->obj_id);
++
++ /*
++ * Check that the object's parent ids match if parent_check requested.
++ *
++ * Tests do not apply to the root object.
++ */
++
++ if (parent_check && tags->obj_id > 1 && !obj->parent)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d obj->parent is NULL",
++ tags->obj_id, oh->parent_obj_id);
++
++ if (parent_check && obj->parent &&
++ oh->parent_obj_id != obj->parent->obj_id &&
++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d parent_obj_id %d",
++ tags->obj_id, oh->parent_obj_id,
++ obj->parent->obj_id);
++
++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is NULL",
++ obj->obj_id);
++
++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is 0xff",
++ obj->obj_id);
++}
++
++void yaffs_verify_file(struct yaffs_obj *obj)
++{
++ u32 x;
++ int required_depth;
++ int actual_depth;
++ int last_chunk;
++ u32 offset_in_chunk;
++ u32 the_chunk;
++
++ u32 i;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ struct yaffs_tnode *tn;
++ u32 obj_id;
++
++ if (!obj)
++ return;
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ dev = obj->my_dev;
++ obj_id = obj->obj_id;
++
++
++ /* Check file size is consistent with tnode depth */
++ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
++ &last_chunk, &offset_in_chunk);
++ last_chunk++;
++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x > 0) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ actual_depth = obj->variant.file_variant.top_level;
++
++ /* Check that the chunks in the tnode tree are all correct.
++ * We do this by scanning through the tnode tree and
++ * checking the tags for every chunk match.
++ */
++
++ if (yaffs_skip_nand_verification(dev))
++ return;
++
++ for (i = 1; i <= last_chunk; i++) {
++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
++
++ if (!tn)
++ continue;
++
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk > 0) {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ &tags);
++ if (tags.obj_id != obj_id || tags.chunk_id != i)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
++ obj_id, i, the_chunk,
++ tags.obj_id, tags.chunk_id);
++ }
++ }
++}
++
++void yaffs_verify_link(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify sane equivalent object */
++}
++
++void yaffs_verify_symlink(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify symlink string */
++}
++
++void yaffs_verify_special(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++}
++
++void yaffs_verify_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++ u32 chunk_min;
++ u32 chunk_max;
++ u32 chunk_id_ok;
++ u32 chunk_in_range;
++ u32 chunk_wrongly_deleted;
++ u32 chunk_valid;
++
++ if (!obj)
++ return;
++
++ if (obj->being_created)
++ return;
++
++ dev = obj->my_dev;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Check sane object header chunk */
++
++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
++ chunk_max =
++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
++
++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
++ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
++ chunk_valid = chunk_in_range &&
++ yaffs_check_chunk_bit(dev,
++ obj->hdr_chunk / dev->param.chunks_per_block,
++ obj->hdr_chunk % dev->param.chunks_per_block);
++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
++
++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has chunk_id %d %s %s",
++ obj->obj_id, obj->hdr_chunk,
++ chunk_id_ok ? "" : ",out of range",
++ chunk_wrongly_deleted ? ",marked as deleted" : "");
++
++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj_hdr *oh;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
++
++ yaffs_verify_oh(obj, oh, &tags, 1);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ /* Verify it has a parent */
++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has parent pointer %p which does not look like an object",
++ obj->obj_id, obj->parent);
++ }
++
++ /* Verify parent is a directory */
++ if (obj->parent &&
++ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d's parent is not a directory (type %d)",
++ obj->obj_id, obj->parent->variant_type);
++ }
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ yaffs_verify_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ yaffs_verify_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ yaffs_verify_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ yaffs_verify_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ yaffs_verify_special(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has illegaltype %d",
++ obj->obj_id, obj->variant_type);
++ break;
++ }
++}
++
++void yaffs_verify_objects(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int i;
++ struct list_head *lh;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Iterate through the objects in each hash entry */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ yaffs_verify_obj(obj);
++ }
++ }
++}
++
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++ int count = 0;
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!obj->parent) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
++ BUG();
++ return;
++ }
++
++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_verify_obj(list_obj);
++ if (obj == list_obj)
++ count++;
++ }
++
++ if (count != 1) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory %d times",
++ count);
++ BUG();
++ }
++}
++
++void yaffs_verify_dir(struct yaffs_obj *directory)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++
++ if (!directory) {
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_full_verification(directory->my_dev))
++ return;
++
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Directory has wrong type: %d",
++ directory->variant_type);
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &directory->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (list_obj->parent != directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory list has wrong parent %p",
++ list_obj->parent);
++ BUG();
++ }
++ yaffs_verify_obj_in_dir(list_obj);
++ }
++}
++
++static int yaffs_free_verification_failures;
++
++void yaffs_verify_free_chunks(struct yaffs_dev *dev)
++{
++ int counted;
++ int difference;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ counted = yaffs_count_free_chunks(dev);
++
++ difference = dev->n_free_chunks - counted;
++
++ if (difference) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Freechunks verification failure %d %d %d",
++ dev->n_free_chunks, counted, difference);
++ yaffs_free_verification_failures++;
++ }
++}
++
++int yaffs_verify_file_sane(struct yaffs_obj *in)
++{
++ (void) in;
++ return YAFFS_OK;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_verify.h linux-3.13.11/fs/yaffs2/yaffs_verify.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_verify.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_VERIFY_H__
++#define __YAFFS_VERIFY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
++ int n);
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n);
++void yaffs_verify_blocks(struct yaffs_dev *dev);
++
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check);
++void yaffs_verify_file(struct yaffs_obj *obj);
++void yaffs_verify_link(struct yaffs_obj *obj);
++void yaffs_verify_symlink(struct yaffs_obj *obj);
++void yaffs_verify_special(struct yaffs_obj *obj);
++void yaffs_verify_obj(struct yaffs_obj *obj);
++void yaffs_verify_objects(struct yaffs_dev *dev);
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
++void yaffs_verify_dir(struct yaffs_obj *directory);
++void yaffs_verify_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_verify_file_sane(struct yaffs_obj *obj);
++
++int yaffs_skip_verification(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_vfs.c linux-3.13.11/fs/yaffs2/yaffs_vfs.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_vfs.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,3600 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * 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 struct yaffs_dev associated with
++ * this superblock
++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
++ * superblock
++ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
++ */
++
++/*
++ * There are two variants of the VFS glue code. This variant should compile
++ * for any version of Linux.
++ */
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
++#define YAFFS_COMPILE_BACKGROUND
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
++#define YAFFS_COMPILE_FREEZER
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
++#define YAFFS_COMPILE_EXPORTFS
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_USE_SETATTR_COPY
++#define YAFFS_USE_TRUNCATE_SETSIZE
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_HAS_EVICT_INODE
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++#define YAFFS_NEW_FOLLOW_LINK 1
++#else
++#define YAFFS_NEW_FOLLOW_LINK 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_HAS_WRITE_SUPER
++#endif
++
++
++#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/fs.h>
++#include <linux/proc_fs.h>
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
++#include <linux/smp_lock.h>
++#endif
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++#include <linux/namei.h>
++#endif
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++#include <linux/exportfs.h>
++#endif
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#endif
++#ifdef YAFFS_COMPILE_FREEZER
++#include <linux/freezer.h>
++#endif
++
++#include <asm/div64.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/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, 26))
++#define YPROC_ROOT (&proc_root)
++#else
++#define YPROC_ROOT NULL
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define Y_INIT_TIMER(a) init_timer(a)
++#else
++#define Y_INIT_TIMER(a) init_timer_on_stack(a)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_SUPER_HAS_DIRTY
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++ uint64_t result = partition_size;
++ do_div(result, block_size);
++ return (uint32_t) result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/mtd/mtd.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#include "yaffs_linux.h"
++
++#include "yaffs_mtdif.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_getblockinfo.h"
++
++unsigned int yaffs_trace_mask =
++ YAFFS_TRACE_BAD_BLOCKS |
++ YAFFS_TRACE_ALWAYS |
++ 0;
++
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++unsigned int yaffs_gc_control = 1;
++unsigned int yaffs_bg_enable = 1;
++unsigned int yaffs_auto_select = 1;
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_trace_mask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++module_param(yaffs_gc_control, uint, 0644);
++module_param(yaffs_bg_enable, uint, 0644);
++#else
++MODULE_PARM(yaffs_trace_mask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++MODULE_PARM(yaffs_gc_control, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
++#else
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_inode_to_obj(iptr) \
++ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
++#else
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define Y_CLEAR_INODE(i) clear_inode(i)
++#else
++#define Y_CLEAR_INODE(i) end_writeback(i)
++#endif
++
++
++#define update_dir_time(dir) do {\
++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++ } while (0)
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj);
++
++
++static void yaffs_gross_lock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
++}
++
++static void yaffs_gross_unlock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
++}
++
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++ /* Lifted from jffs2 */
++
++ struct yaffs_obj *obj;
++ unsigned char *pg_buf;
++ int ret;
++ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readpage_nolock at %lld, size %08x",
++ (long long)pos,
++ (unsigned)PAGE_CACHE_SIZE);
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++#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_gross_lock(dev);
++
++ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
++
++ yaffs_gross_unlock(dev);
++
++ if (ret >= 0)
++ ret = 0;
++
++ if (ret) {
++ ClearPageUptodate(pg);
++ SetPageError(pg);
++ } else {
++ SetPageUptodate(pg);
++ ClearPageError(pg);
++ }
++
++ flush_dcache_page(pg);
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
++ 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)
++{
++ int ret;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
++ ret = yaffs_readpage_unlock(f, pg);
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
++ return ret;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
++#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
++#else
++#define YCRED_FSUID() YCRED(current)->fsuid
++#define YCRED_FSGID() YCRED(current)->fsgid
++
++static inline uid_t i_uid_read(const struct inode *inode)
++{
++ return inode->i_uid;
++}
++
++static inline gid_t i_gid_read(const struct inode *inode)
++{
++ return inode->i_gid;
++}
++
++static inline void i_uid_write(struct inode *inode, uid_t uid)
++{
++ inode->i_uid = uid;
++}
++
++static inline void i_gid_write(struct inode *inode, gid_t gid)
++{
++ inode->i_gid = gid;
++}
++#endif
++
++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc)
++ lc->dirty = val;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb)
++ sb->s_dirt = val;
++ }
++#endif
++
++}
++
++static void yaffs_set_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 1);
++}
++
++static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 0);
++}
++
++static int yaffs_check_super_dirty(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc && lc->dirty)
++ return 1;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb && sb->s_dirt)
++ return 1;
++ }
++#endif
++ return 0;
++
++}
++
++#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 yaffs_dev *dev;
++ struct address_space *mapping = page->mapping;
++ struct inode *inode;
++ unsigned long end_index;
++ char *buffer;
++ struct yaffs_obj *obj;
++ int n_written = 0;
++ unsigned n_bytes;
++ loff_t i_size;
++
++ if (!mapping)
++ BUG();
++ inode = mapping->host;
++ if (!inode)
++ BUG();
++ i_size = i_size_read(inode);
++
++ end_index = i_size >> PAGE_CACHE_SHIFT;
++
++ if (page->index < end_index)
++ n_bytes = PAGE_CACHE_SIZE;
++ else {
++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
++
++ if (page->index > end_index || !n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, inode size = %lld!!",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
++ inode->i_size);
++ yaffs_trace(YAFFS_TRACE_OS,
++ " -> don't care!!");
++
++ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ return 0;
++ }
++ }
++
++ if (n_bytes != PAGE_CACHE_SIZE)
++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
++
++ get_page(page);
++
++ buffer = kmap(page);
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, size %08x",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag0: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ n_written = yaffs_wr_file(obj, buffer,
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag1: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ yaffs_gross_unlock(dev);
++
++ kunmap(page);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ put_page(page);
++
++ return (n_written == n_bytes) ? 0 : -ENOSPC;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ int n_free_chunks;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ n_free_chunks = yaffs_get_n_free_chunks(dev);
++
++ yaffs_gross_unlock(dev);
++
++ return (n_free_chunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_gross_unlock(dev);
++}
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{
++ struct page *pg = NULL;
++ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++ int ret = 0;
++ int space_held = 0;
++
++ /* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++ pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++ pg = __grab_cache_page(mapping, index);
++#endif
++
++ *pagep = pg;
++ if (!pg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "start yaffs_write_begin index %d(%x) uptodate %d",
++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
++
++ /* Get fs space */
++ space_held = yaffs_hold_space(filp);
++
++ if (!space_held) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ /* Update page if required */
++
++ if (!Page_Uptodate(pg))
++ ret = yaffs_readpage_nolock(filp, pg);
++
++ if (ret)
++ goto out;
++
++ /* Happy path return */
++ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
++
++ return 0;
++
++out:
++ yaffs_trace(YAFFS_TRACE_OS,
++ "end yaffs_write_begin fail returning %d", ret);
++ if (space_held)
++ yaffs_release_space(filp);
++ if (pg) {
++ unlock_page(pg);
++ page_cache_release(pg);
++ }
++ return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to)
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
++
++ if (!Page_Uptodate(pg))
++ return yaffs_readpage_nolock(f, pg);
++ return 0;
++}
++#endif
++
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t * pos)
++{
++ struct yaffs_obj *obj;
++ int n_written;
++ loff_t ipos;
++ struct inode *inode;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: hey obj is null!");
++ return -EINVAL;
++ }
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
++ (unsigned)n, (unsigned)n, obj->obj_id, ipos);
++
++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: %d(%x) bytes written",
++ (unsigned)n, (unsigned)n);
++
++ if (n_written > 0) {
++ ipos += n_written;
++ *pos = ipos;
++ if (ipos > inode->i_size) {
++ inode->i_size = ipos;
++ inode->i_blocks = (ipos + 511) >> 9;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write size updated to %lld bytes, %d blocks",
++ ipos, (int)(inode->i_blocks));
++ }
++
++ }
++ yaffs_gross_unlock(dev);
++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
++}
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata)
++{
++ int ret = 0;
++ void *addr, *kva;
++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++ kva = kmap(pg);
++ addr = kva + offset_into_page;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end addr %p pos %lld n_bytes %d",
++ addr, pos, copied);
++
++ ret = yaffs_file_write(filp, addr, copied, &pos);
++
++ if (ret != copied) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end not same size ret %d copied %d",
++ ret, copied);
++ SetPageError(pg);
++ }
++
++ kunmap(pg);
++
++ yaffs_release_space(filp);
++ unlock_page(pg);
++ page_cache_release(pg);
++ return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to)
++{
++ void *addr, *kva;
++
++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++ int n_bytes = to - offset;
++ int n_written;
++
++ kva = kmap(pg);
++ addr = kva + offset;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write addr %p pos %lld n_bytes %d",
++ addr, pos, n_bytes);
++
++ n_written = yaffs_file_write(f, addr, n_bytes, &pos);
++
++ if (n_written != n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write not same size n_written %d n_bytes %d",
++ n_written, n_bytes);
++ SetPageError(pg);
++ }
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write returning %d",
++ n_written == n_bytes ? 0 : n_written);
++
++ return n_written == n_bytes ? 0 : n_written;
++}
++#endif
++
++static struct address_space_operations yaffs_file_address_operations = {
++ .readpage = yaffs_readpage,
++ .writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++ .write_begin = yaffs_write_begin,
++ .write_end = yaffs_write_end,
++#else
++ .prepare_write = yaffs_prepare_write,
++ .commit_write = yaffs_commit_write,
++#endif
++};
++
++
++#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
++{
++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_flush object %d (%s)",
++ obj->obj_id,
++ obj->dirty ? "dirty" : "clean");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_file(obj, 1, 0);
++
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync)
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync)
++#endif
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++ struct dentry *dentry = file->f_path.dentry;
++#endif
++
++ obj = yaffs_dentry_to_obj(dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_object");
++ yaffs_gross_lock(dev);
++ yaffs_flush_file(obj, 1, datasync);
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const 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,
++ .llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const 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 const 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
++
++
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++ void *kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + start, 0, end - start);
++ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(page);
++}
++#endif
++
++
++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
++{
++#ifdef YAFFS_USE_TRUNCATE_SETSIZE
++ truncate_setsize(inode, newsize);
++ return 0;
++#else
++ truncate_inode_pages(&inode->i_data, newsize);
++ return 0;
++#endif
++
++}
++
++
++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
++{
++#ifdef YAFFS_USE_SETATTR_COPY
++ setattr_copy(inode, attr);
++ return 0;
++#else
++ return inode_setattr(inode, attr);
++#endif
++
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_setattr of object %d",
++ yaffs_inode_to_obj(inode)->obj_id);
++#if 0
++ /* Fail if a requested resize >= 2GB */
++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
++ error = -EINVAL;
++#endif
++
++ if (error == 0)
++ error = inode_change_ok(inode, attr);
++ if (error == 0) {
++ int result;
++ if (!error) {
++ error = yaffs_vfs_setattr(inode, attr);
++ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_vfs_setsize(inode, attr->ia_size);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++ }
++ }
++ dev = yaffs_inode_to_obj(inode)->my_dev;
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "resize to %d(%x)",
++ (int)(attr->ia_size),
++ (int)(attr->ia_size));
++ }
++ yaffs_gross_lock(dev);
++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
++ if (result == YAFFS_OK) {
++ error = 0;
++ } else {
++ error = -EPERM;
++ }
++ yaffs_gross_unlock(dev);
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_set_xattrib(obj, name, value, size, flags);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
++ void *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_getxattr \"%s\" from object %d",
++ name, obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_get_xattrib(obj, name, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_removexattr(struct dentry *dentry, const char *name)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_remove_xattrib(obj, name);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_list_xattrib(obj, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr done returning %d", error);
++
++ return error;
++}
++
++
++static const struct inode_operations yaffs_file_inode_operations = {
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++ int buflen)
++{
++ unsigned char *alias;
++ int ret;
++
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++
++ yaffs_gross_unlock(dev);
++
++ if (!alias)
++ return -ENOMEM;
++
++ ret = vfs_readlink(dentry, buffer, buflen, alias);
++ kfree(alias);
++ return ret;
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ void *ret;
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int ret
++#endif
++ unsigned char *alias;
++ int ret_int = 0;
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++ yaffs_gross_unlock(dev);
++
++ if (!alias) {
++ ret_int = -ENOMEM;
++ goto out;
++ }
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ nd_set_link(nd, alias);
++ ret = alias;
++out:
++ if (ret_int)
++ ret = ERR_PTR(ret_int);
++ return ret;
++#else
++ ret = vfs_follow_link(nd, alias);
++ kfree(alias);
++out:
++ if (ret_int)
++ ret = ret_int;
++ return ret;
++#endif
++}
++
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* 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)
++{
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_put_inode: ino %d, count %d"),
++ (int)inode->i_ino, atomic_read(&inode->i_count);
++
++}
++#endif
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++{
++ kfree(alias);
++}
++#endif
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++ .readlink = yaffs_readlink,
++ .follow_link = yaffs_follow_link,
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ .put_link = yaffs_put_link,
++#endif
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++ struct inode *inode;
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return 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_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ yaffs_gross_unlock(dev);
++
++ unlock_new_inode(inode);
++ return inode;
++}
++
++#else
++
++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.
++ */
++
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_inode for %d", (int)inode->i_ino);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++}
++
++#endif
++
++
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ struct yaffs_obj *obj)
++{
++ struct inode *inode;
++
++ if (!sb) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL super_block!!");
++ return NULL;
++
++ }
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL object!!");
++ return NULL;
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for object %d", obj->obj_id);
++
++ inode = Y_IGET(sb, obj->obj_id);
++ if (IS_ERR(inode))
++ return NULL;
++
++ /* NB Side effect: iget calls back to yaffs_read_inode(). */
++ /* iget also increments the inode's i_count */
++ /* NB You can't be holding gross_lock or deadlock will happen! */
++
++ return inode;
++}
++
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++ dev_t rdev)
++#elif (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;
++
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_dev *dev;
++
++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
++
++ int error = -ENOSPC;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++ mode |= S_ISGID;
++
++ if (parent) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: parent object %d type %d",
++ parent->obj_id, parent->variant_type);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: could not get parent object");
++ return -EPERM;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: making oject for %s, mode %x dev %x",
++ dentry->d_name.name, mode, rdev);
++
++ dev = parent->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ switch (mode & S_IFMT) {
++ default:
++ /* Special (socket, fifo, device...) */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, old_encode_dev(rdev));
++#else
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, rdev);
++#endif
++ break;
++ case S_IFREG: /* file */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
++ gid);
++ break;
++ case S_IFDIR: /* directory */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
++ uid, gid);
++ break;
++ case S_IFLNK: /* symlink */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
++ obj = NULL; /* Do we ever get here? */
++ break;
++ }
++
++ /* Can not call yaffs_get_inode() with gross lock held */
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod created object %d count = %d",
++ obj->obj_id, atomic_read(&inode->i_count));
++ error = 0;
++ yaffs_fill_inode_from_obj(dir, parent);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
++ error = -ENOMEM;
++ }
++
++ return error;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++#else
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++ int ret_val;
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++ return ret_val;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ bool dummy)
++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ struct nameidata *n)
++#elif (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
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ unsigned int dummy)
++#elif (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
++{
++ struct yaffs_obj *obj;
++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
++
++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
++
++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
++
++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
++
++ /* Can't hold gross lock when calling yaffs_get_inode() */
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_lookup found %d", obj->obj_id);
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
++
++ }
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *link = NULL;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
++ link =
++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ obj);
++
++ if (link) {
++ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
++ d_instantiate(dentry, old_dentry->d_inode);
++ atomic_inc(&old_dentry->d_inode->i_count);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_link link count %d i_count %d",
++ old_dentry->d_inode->i_nlink,
++ atomic_read(&old_dentry->d_inode->i_count));
++ }
++
++ yaffs_gross_unlock(dev);
++
++ if (link) {
++ update_dir_time(dir);
++ return 0;
++ }
++
++ return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
++
++ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ return -ENAMETOOLONG;
++
++ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
++ YAFFS_MAX_ALIAS_LENGTH)
++ return -ENAMETOOLONG;
++
++ dev = yaffs_inode_to_obj(dir)->my_dev;
++ yaffs_gross_lock(dev);
++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ S_IFLNK | S_IRWXUGO, uid, gid, symname);
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ struct inode *inode;
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
++ return 0;
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
++ }
++
++ return -ENOMEM;
++}
++
++/*
++ * 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)
++{
++ struct yaffs_dev *dev;
++ int ret_val = YAFFS_FAIL;
++ struct yaffs_obj *target;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
++ dev = yaffs_inode_to_obj(old_dir)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ /* Check if the target is an existing directory that is not empty. */
++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++
++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !list_empty(&target->variant.dir_variant.children)) {
++
++ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
++
++ ret_val = YAFFS_FAIL;
++ } else {
++ /* Now does unlinking internally using shadowing mechanism */
++ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
++
++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
++ old_dentry->d_name.name,
++ yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++ }
++ yaffs_gross_unlock(dev);
++
++ if (ret_val == YAFFS_OK) {
++ if (target)
++ inode_dec_link_count(new_dentry->d_inode);
++
++ update_dir_time(old_dir);
++ if (old_dir != new_dir)
++ update_dir_time(new_dir);
++ return 0;
++ } else {
++ return -ENOTEMPTY;
++ }
++}
++
++
++
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int ret_val;
++
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
++ (int)(dir->i_ino), dentry->d_name.name);
++ obj = yaffs_inode_to_obj(dir);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ ret_val = yaffs_unlinker(obj, dentry->d_name.name);
++
++ if (ret_val == YAFFS_OK) {
++ inode_dec_link_count(dentry->d_inode);
++ dir->i_version++;
++ yaffs_gross_unlock(dev);
++ update_dir_time(dir);
++ return 0;
++ }
++ yaffs_gross_unlock(dev);
++ return -ENOTEMPTY;
++}
++
++
++
++static const 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,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the remove_obj_fn to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each struct yaffs_dev has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_search_context {
++ struct yaffs_dev *dev;
++ struct yaffs_obj *dir_obj;
++ struct yaffs_obj *next_return;
++ struct list_head others;
++};
++
++/*
++ * yaffs_new_search() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
++{
++ struct yaffs_dev *dev = dir->my_dev;
++ struct yaffs_search_context *sc =
++ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
++ if (sc) {
++ sc->dir_obj = dir;
++ sc->dev = dev;
++ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else
++ sc->next_return =
++ list_entry(dir->variant.dir_variant.children.next,
++ struct yaffs_obj, siblings);
++ INIT_LIST_HEAD(&sc->others);
++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
++ }
++ return sc;
++}
++
++/*
++ * yaffs_search_end() disposes of a search context and cleans up.
++ */
++static void yaffs_search_end(struct yaffs_search_context *sc)
++{
++ if (sc) {
++ list_del(&sc->others);
++ kfree(sc);
++ }
++}
++
++/*
++ * yaffs_search_advance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_search_advance(struct yaffs_search_context *sc)
++{
++ if (!sc)
++ return;
++
++ if (sc->next_return == NULL ||
++ list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else {
++ struct list_head *next = sc->next_return->siblings.next;
++
++ if (next == &sc->dir_obj->variant.dir_variant.children)
++ sc->next_return = NULL; /* end of list */
++ else
++ sc->next_return =
++ list_entry(next, struct yaffs_obj, siblings);
++ }
++}
++
++/*
++ * yaffs_remove_obj_callback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
++{
++
++ struct list_head *i;
++ struct yaffs_search_context *sc;
++ struct list_head *search_contexts =
++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
++
++ /* Iterate through the directory search contexts.
++ * If any are currently on the object being removed, then advance
++ * the search context to the next object to prevent a hanging pointer.
++ */
++ list_for_each(i, search_contexts) {
++ sc = list_entry(i, struct yaffs_search_context, others);
++ if (sc->next_return == obj)
++ yaffs_search_advance(sc);
++ }
++
++}
++
++
++/*-----------------------------------------------------------------*/
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++static int yaffs_readdir(struct file *file, struct dir_context *ctx)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = file->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(file->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = ctx->pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)file->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dotdot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++
++ curoffs = 1;
++
++ /* If the directory has changed since the open or last call to
++ readdir, rewind to after the 2 canned entries. */
++ if (file->f_version != inode->i_version) {
++ offset = 2;
++ ctx->pos = offset;
++ file->f_version = inode->i_version;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (!dir_emit(ctx, name, strlen(name),
++ this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ ctx->pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#else
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = f->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = f->f_pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ f->f_pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)f->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, "..", 2, offset,
++ f->f_dentry->d_parent->d_inode->i_ino,
++ DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ 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;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (filldir(dirent,
++ name,
++ strlen(name),
++ offset, this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ f->f_pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#endif
++
++static const struct file_operations yaffs_dir_operations = {
++ .read = generic_read_dir,
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++ .iterate = yaffs_readdir,
++#else
++ .readdir = yaffs_readdir,
++#endif
++ .fsync = yaffs_sync_object,
++ .llseek = generic_file_llseek,
++};
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj)
++{
++ if (inode && obj) {
++
++ /* Check mode against the variant type and attempt to repair if broken. */
++ u32 mode = obj->yst_mode;
++ switch (obj->variant_type) {
++ 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_flags |= S_NOATIME;
++
++ inode->i_ino = obj->obj_id;
++ inode->i_mode = obj->yst_mode;
++ i_uid_write(inode, obj->yst_uid);
++ i_gid_write(inode, 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_get_obj_length(obj);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++
++ set_nlink(inode, yaffs_get_obj_link_count(obj));
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
++ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
++ 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_inode_to_obj_lv(inode) = obj;
++
++ obj->my_inode = inode;
++
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode invalid parameters");
++ }
++
++}
++
++
++
++/*
++ * yaffs background thread functions .
++ * yaffs_bg_thread_fn() the thread function
++ * yaffs_bg_start() launches the background thread.
++ * yaffs_bg_stop() cleans up the background thread.
++ *
++ * NB:
++ * The thread should only run after the yaffs is initialised
++ * The thread should be stopped before yaffs is unmounted.
++ * The thread should not do any writing while the fs is in read only.
++ */
++
++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
++{
++ unsigned erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned scattered = 0; /* Free chunks not in an erased block */
++
++ if (erased_chunks < dev->n_free_chunks)
++ scattered = (dev->n_free_chunks - erased_chunks);
++
++ if (!context->bg_running)
++ return 0;
++ else if (scattered < (dev->param.chunks_per_block * 2))
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 2)
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 4)
++ return 1;
++ else
++ return 2;
++}
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++
++void yaffs_background_waker(unsigned long data)
++{
++ wake_up_process((struct task_struct *)data);
++}
++
++static int yaffs_bg_thread_fn(void *data)
++{
++ struct yaffs_dev *dev = (struct yaffs_dev *)data;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned long now = jiffies;
++ unsigned long next_dir_update = now;
++ unsigned long next_gc = now;
++ unsigned long expires;
++ unsigned int urgency;
++
++ int gc_result;
++ struct timer_list timer;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "yaffs_background starting for dev %p", (void *)dev);
++
++#ifdef YAFFS_COMPILE_FREEZER
++ set_freezable();
++#endif
++ while (context->bg_running) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
++
++ if (kthread_should_stop())
++ break;
++
++#ifdef YAFFS_COMPILE_FREEZER
++ if (try_to_freeze())
++ continue;
++#endif
++ yaffs_gross_lock(dev);
++
++ now = jiffies;
++
++ if (time_after(now, next_dir_update) && yaffs_bg_enable) {
++ yaffs_update_dirty_dirs(dev);
++ next_dir_update = now + HZ;
++ }
++
++ if (time_after(now, next_gc) && yaffs_bg_enable) {
++ if (!dev->is_checkpointed) {
++ urgency = yaffs_bg_gc_urgency(dev);
++ gc_result = yaffs_bg_gc(dev, urgency);
++ if (urgency > 1)
++ next_gc = now + HZ / 20 + 1;
++ else if (urgency > 0)
++ next_gc = now + HZ / 10 + 1;
++ else
++ next_gc = now + HZ * 2;
++ } else {
++ /*
++ * gc not running so set to next_dir_update
++ * to cut down on wake ups
++ */
++ next_gc = next_dir_update;
++ }
++ }
++ yaffs_gross_unlock(dev);
++#if 1
++ expires = next_dir_update;
++ if (time_before(next_gc, expires))
++ expires = next_gc;
++ if (time_before(expires, now))
++ expires = now + HZ;
++
++ Y_INIT_TIMER(&timer);
++ timer.expires = expires + 1;
++ timer.data = (unsigned long)current;
++ timer.function = yaffs_background_waker;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_timer(&timer);
++ schedule();
++ del_timer_sync(&timer);
++#else
++ msleep(10);
++#endif
++ }
++
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ int retval = 0;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++
++ if (dev->read_only)
++ return -1;
++
++ context->bg_running = 1;
++
++ context->bg_thread = kthread_run(yaffs_bg_thread_fn,
++ (void *)dev, "yaffs-bg-%d",
++ context->mount_id);
++
++ if (IS_ERR(context->bg_thread)) {
++ retval = PTR_ERR(context->bg_thread);
++ context->bg_thread = NULL;
++ context->bg_running = 0;
++ }
++ return retval;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
++
++ ctxt->bg_running = 0;
++
++ if (ctxt->bg_thread) {
++ kthread_stop(ctxt->bg_thread);
++ ctxt->bg_thread = NULL;
++ }
++}
++#else
++static int yaffs_bg_thread_fn(void *data)
++{
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ return 0;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++}
++#endif
++
++
++static void yaffs_flush_inodes(struct super_block *sb)
++{
++ struct inode *iptr;
++ struct yaffs_obj *obj;
++
++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
++ obj = yaffs_inode_to_obj(iptr);
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "flushing obj %d",
++ obj->obj_id);
++ yaffs_flush_file(obj, 1, 0);
++ }
++ }
++}
++
++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ if (!dev)
++ return;
++
++ yaffs_flush_inodes(sb);
++ yaffs_update_dirty_dirs(dev);
++ yaffs_flush_whole_cache(dev);
++ if (do_checkpoint)
++ yaffs_checkpoint_save(dev);
++}
++
++static LIST_HEAD(yaffs_context_list);
++struct mutex yaffs_context_lock;
++
++static void yaffs_put_super(struct super_block *sb)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super");
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "Shutting down yaffs background thread");
++ yaffs_bg_stop(dev);
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "yaffs background thread shut down");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_super(sb, 1);
++
++ yaffs_deinitialise(dev);
++
++ yaffs_gross_unlock(dev);
++
++ mutex_lock(&yaffs_context_lock);
++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
++ mutex_unlock(&yaffs_context_lock);
++
++ if (yaffs_dev_to_lc(dev)->spare_buffer) {
++ kfree(yaffs_dev_to_lc(dev)->spare_buffer);
++ yaffs_dev_to_lc(dev)->spare_buffer = NULL;
++ }
++
++ kfree(dev);
++
++ yaffs_put_mtd_device(mtd);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super done");
++}
++
++
++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
++{
++ return yaffs_gc_control;
++}
++
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++
++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
++ uint32_t generation)
++{
++ return Y_IGET(sb, ino);
++}
++
++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++struct dentry *yaffs2_get_parent(struct dentry *dentry)
++{
++
++ struct super_block *sb = dentry->d_inode->i_sb;
++ struct dentry *parent = ERR_PTR(-ENOENT);
++ struct inode *inode;
++ unsigned long parent_ino;
++ struct yaffs_obj *d_obj;
++ struct yaffs_obj *parent_obj;
++
++ d_obj = yaffs_inode_to_obj(dentry->d_inode);
++
++ if (d_obj) {
++ parent_obj = d_obj->parent;
++ if (parent_obj) {
++ parent_ino = yaffs_get_obj_inode(parent_obj);
++ inode = Y_IGET(sb, parent_ino);
++
++ if (IS_ERR(inode)) {
++ parent = ERR_CAST(inode);
++ } else {
++ parent = d_obtain_alias(inode);
++ if (!IS_ERR(parent)) {
++ parent = ERR_PTR(-ENOMEM);
++ iput(inode);
++ }
++ }
++ }
++ }
++
++ return parent;
++}
++
++/* Just declare a zero structure as a NULL value implies
++ * using the default functions of exportfs.
++ */
++
++static struct export_operations yaffs_export_ops = {
++ .fh_to_dentry = yaffs2_fh_to_dentry,
++ .fh_to_parent = yaffs2_fh_to_parent,
++ .get_parent = yaffs2_get_parent,
++};
++
++#endif
++
++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
++{
++ /* Clear the association between the inode and
++ * the struct yaffs_obj.
++ */
++ obj->my_inode = NULL;
++ yaffs_inode_to_obj_lv(inode) = NULL;
++
++ /* If the object freeing was deferred, then the real
++ * free happens now.
++ * This should fix the inode inconsistency problem.
++ */
++ yaffs_handle_defered_free(obj);
++}
++
++#ifdef YAFFS_HAS_EVICT_INODE
++/* yaffs_evict_inode combines into one operation what was previously done in
++ * yaffs_clear_inode() and yaffs_delete_inode()
++ *
++ */
++static void yaffs_evict_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ int deleteme = 0;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_evict_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (!inode->i_nlink && !is_bad_inode(inode))
++ deleteme = 1;
++ truncate_inode_pages(&inode->i_data, 0);
++ Y_CLEAR_INODE(inode);
++
++ if (deleteme && obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(dev);
++ }
++}
++#else
++
++/* clear is called to tell the fs to release any per-inode data it holds.
++ * The object might still exist on disk and is just being thrown out of the cache
++ * or else the object has actually been deleted and we're being called via
++ * the chain
++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
++ */
++
++static void yaffs_clear_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_clear_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(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)
++{
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_delete_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ truncate_inode_pages(&inode->i_data, 0);
++#endif
++ clear_inode(inode);
++}
++#endif
++
++
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++ 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)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#endif
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
++
++ yaffs_gross_lock(dev);
++
++ buf->f_type = YAFFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_namelen = 255;
++
++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
++ /* Do this if chunk size is not a power of 2 */
++
++ uint64_t bytes_in_dev;
++ uint64_t bytes_free;
++
++ bytes_in_dev =
++ ((uint64_t)
++ ((dev->param.end_block - dev->param.start_block +
++ 1))) * ((uint64_t) (dev->param.chunks_per_block *
++ dev->data_bytes_per_chunk));
++
++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
++ buf->f_blocks = bytes_in_dev;
++
++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
++ ((uint64_t) (dev->data_bytes_per_chunk));
++
++ do_div(bytes_free, sb->s_blocksize);
++
++ buf->f_bfree = bytes_free;
++
++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
++
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ } else {
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++ }
++
++ buf->f_files = 0;
++ buf->f_ffree = 0;
++ buf->f_bavail = buf->f_bfree;
++
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++
++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
++{
++
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
++ int do_checkpoint;
++ int dirty = yaffs_check_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
++ gc_urgent,
++ dirty ? "dirty" : "clean",
++ request_checkpoint ? "checkpoint requested" : "no checkpoint",
++ oneshot_checkpoint ? " one-shot" : "");
++
++ yaffs_gross_lock(dev);
++ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
++ oneshot_checkpoint) && !dev->is_checkpointed;
++
++ if (dirty || do_checkpoint) {
++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
++ yaffs_clear_super_dirty(dev);
++ if (oneshot_checkpoint)
++ yaffs_auto_checkpoint &= ~4;
++ }
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#ifdef YAFFS_HAS_WRITE_SUPER
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_write_super %s",
++ request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++ return 0;
++#endif
++}
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++ return 0;
++}
++
++
++
++static const struct super_operations yaffs_super_ops = {
++ .statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++ .read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++ .put_inode = yaffs_put_inode,
++#endif
++ .put_super = yaffs_put_super,
++#ifdef YAFFS_HAS_EVICT_INODE
++ .evict_inode = yaffs_evict_inode,
++#else
++ .delete_inode = yaffs_delete_inode,
++ .clear_inode = yaffs_clear_inode,
++#endif
++ .sync_fs = yaffs_sync_fs,
++#ifdef YAFFS_HAS_WRITE_SUPER
++ .write_super = yaffs_write_super,
++#endif
++};
++
++struct yaffs_options {
++ int inband_tags;
++ int skip_checkpoint_read;
++ int skip_checkpoint_write;
++ int no_cache;
++ int tags_ecc_on;
++ int tags_ecc_overridden;
++ int lazy_loading_enabled;
++ int lazy_loading_overridden;
++ int empty_lost_and_found;
++ int empty_lost_and_found_overridden;
++ int disable_summary;
++};
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(struct 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++;
++
++ 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, "tags-ecc-off")) {
++ options->tags_ecc_on = 0;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "tags-ecc-on")) {
++ options->tags_ecc_on = 1;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-off")) {
++ options->lazy_loading_enabled = 0;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-on")) {
++ options->lazy_loading_enabled = 1;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "disable-summary")) {
++ options->disable_summary = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
++ options->empty_lost_and_found = 0;
++ options->empty_lost_and_found_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
++ options->empty_lost_and_found = 1;
++ options->empty_lost_and_found_overridden = 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 dentry *yaffs_make_root(struct inode *inode)
++{
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++ struct dentry *root = d_alloc_root(inode);
++
++ if (!root)
++ iput(inode);
++
++ return root;
++#else
++ return d_make_root(inode);
++#endif
++}
++
++
++
++
++static struct super_block *yaffs_internal_read_super(int yaffs_version,
++ struct super_block *sb,
++ void *data, int silent)
++{
++ int n_blocks;
++ struct inode *inode = NULL;
++ struct dentry *root;
++ struct yaffs_dev *dev = 0;
++ char devname_buf[BDEVNAME_SIZE + 1];
++ struct mtd_info *mtd;
++ int err;
++ char *data_str = (char *)data;
++ struct yaffs_linux_context *context = NULL;
++ struct yaffs_param *param;
++
++ int read_only = 0;
++ int inband_tags = 0;
++
++ struct yaffs_options options;
++
++ unsigned mount_id;
++ int found;
++ struct yaffs_linux_context *context_iterator;
++ struct list_head *l;
++
++ if (!sb) {
++ printk(KERN_INFO "yaffs: sb is NULL\n");
++ return NULL;
++ }
++
++ sb->s_magic = YAFFS_MAGIC;
++ sb->s_op = &yaffs_super_ops;
++ sb->s_flags |= MS_NOATIME;
++
++ read_only = ((sb->s_flags & MS_RDONLY) != 0);
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++ sb->s_export_op = &yaffs_export_ops;
++#endif
++
++ 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\" %s\n",
++ sb->s_dev,
++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
++
++ 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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: Using yaffs%d", yaffs_version);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
++ MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ yaffs_devname(sb, devname_buf));
++
++ /* Get the device */
++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++ if (IS_ERR(mtd)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device %u either not valid or unavailable",
++ MINOR(sb->s_dev));
++ return NULL;
++ }
++
++ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
++ yaffs_version = 2;
++ }
++
++ /* Added NCB 26/5/2006 for completeness */
++ if (yaffs_version == 2 && !options.inband_tags
++ && WRITE_SIZE(mtd) == 512) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
++ yaffs_version = 1;
++ }
++
++ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
++ options.inband_tags)
++ inband_tags = 1;
++
++ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++ 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 struct yaffs_dev up for mtd
++ */
++
++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++ read_only = 1;
++ printk(KERN_INFO
++ "yaffs: mtd is read only, setting superblock read only\n"
++ );
++ sb->s_flags |= MS_RDONLY;
++ }
++
++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
++
++ if (!dev || !context) {
++ kfree(dev);
++ kfree(context);
++ dev = NULL;
++ context = NULL;
++
++ /* Deep shit could not allocate device structure */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
++ );
++ return NULL;
++ }
++ memset(dev, 0, sizeof(struct yaffs_dev));
++ param = &(dev->param);
++
++ memset(context, 0, sizeof(struct yaffs_linux_context));
++ dev->os_context = context;
++ INIT_LIST_HEAD(&(context->context_list));
++ context->dev = dev;
++ context->super = sb;
++
++ dev->read_only = read_only;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ sb->s_fs_info = dev;
++#else
++ sb->u.generic_sbp = dev;
++#endif
++
++
++ dev->driver_context = mtd;
++ param->name = mtd->name;
++
++ /* Set up the memory size parameters.... */
++
++
++ param->n_reserved_blocks = 5;
++ param->n_caches = (options.no_cache) ? 0 : 10;
++ param->inband_tags = inband_tags;
++
++ param->enable_xattr = 1;
++ if (options.lazy_loading_overridden)
++ param->disable_lazy_load = !options.lazy_loading_enabled;
++
++ param->defered_dir_update = 1;
++
++ if (options.tags_ecc_overridden)
++ param->no_tags_ecc = !options.tags_ecc_on;
++
++ param->empty_lost_n_found = 1;
++ param->refresh_period = 500;
++ param->disable_summary = options.disable_summary;
++
++
++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
++ param->disable_bad_block_marking = 1;
++#endif
++ if (options.empty_lost_and_found_overridden)
++ param->empty_lost_n_found = options.empty_lost_and_found;
++
++ /* ... and the functions. */
++ if (yaffs_version == 2) {
++ param->is_yaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ param->total_bytes_per_chunk = mtd->writesize;
++ param->chunks_per_block = mtd->erasesize / mtd->writesize;
++#else
++ param->total_bytes_per_chunk = mtd->oobblock;
++ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
++#endif
++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++ } else {
++ param->is_yaffs2 = 0;
++ n_blocks = YCALCBLOCKS(mtd->size,
++ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
++
++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
++ }
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++
++ yaffs_mtd_drv_install(dev);
++
++ param->sb_dirty_fn = yaffs_set_super_dirty;
++ param->gc_control_fn = yaffs_gc_control_callback;
++
++ yaffs_dev_to_lc(dev)->super = sb;
++
++ param->use_nand_ecc = 1;
++
++ param->skip_checkpt_rd = options.skip_checkpoint_read;
++ param->skip_checkpt_wr = options.skip_checkpoint_write;
++
++ mutex_lock(&yaffs_context_lock);
++ /* Get a mount id */
++ found = 0;
++ for (mount_id = 0; !found; mount_id++) {
++ found = 1;
++ list_for_each(l, &yaffs_context_list) {
++ context_iterator =
++ list_entry(l, struct yaffs_linux_context,
++ context_list);
++ if (context_iterator->mount_id == mount_id)
++ found = 0;
++ }
++ }
++ context->mount_id = mount_id;
++
++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
++ &yaffs_context_list);
++ mutex_unlock(&yaffs_context_lock);
++
++ /* Directory search handling... */
++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
++ param->remove_obj_fn = yaffs_remove_obj_callback;
++
++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
++
++ yaffs_gross_lock(dev);
++
++ err = yaffs_guts_initialise(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: guts initialised %s",
++ (err == YAFFS_OK) ? "OK" : "FAILED");
++
++ if (err == YAFFS_OK)
++ yaffs_bg_start(dev);
++
++ if (!context->bg_thread)
++ param->defered_dir_update = 0;
++
++ sb->s_maxbytes = yaffs_max_file_size(dev);
++
++ /* Release lock before yaffs_get_inode() */
++ yaffs_gross_unlock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
++
++ root = yaffs_make_root(inode);
++
++ if (!root)
++ return NULL;
++
++ sb->s_root = root;
++ if(!dev->is_checkpointed)
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
++ 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, 39))
++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs_mount,
++#else
++ .get_sb = yaffs_read_super,
++#endif
++ .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
++
++
++#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, 39))
++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs2_mount,
++#else
++ .get_sb = yaffs2_read_super,
++#endif
++ .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
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++static struct proc_dir_entry *my_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
++{
++ struct yaffs_param *param = &dev->param;
++ int bs[10];
++
++ yaffs_count_blocks_by_state(dev,bs);
++
++ buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
++ buf += sprintf(buf, "end_block............ %d\n", param->end_block);
++ buf += sprintf(buf, "total_bytes_per_chunk %d\n",
++ param->total_bytes_per_chunk);
++ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
++ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
++ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
++ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
++ buf += sprintf(buf, "empty_lost_n_found... %d\n",
++ param->empty_lost_n_found);
++ buf += sprintf(buf, "disable_lazy_load.... %d\n",
++ param->disable_lazy_load);
++ buf += sprintf(buf, "disable_bad_block_mrk %d\n",
++ param->disable_bad_block_marking);
++ buf += sprintf(buf, "refresh_period....... %d\n",
++ param->refresh_period);
++ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
++ buf += sprintf(buf, "n_reserved_blocks.... %d\n",
++ param->n_reserved_blocks);
++ buf += sprintf(buf, "always_check_erased.. %d\n",
++ param->always_check_erased);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "block count by state\n");
++ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
++ bs[0], bs[1], bs[2], bs[3], bs[4]);
++ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
++ bs[5], bs[6], bs[7], bs[8], bs[9]);
++
++ return buf;
++}
++
++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
++{
++ buf += sprintf(buf, "max file size....... %lld\n",
++ (long long) yaffs_max_file_size(dev));
++ buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
++ dev->data_bytes_per_chunk);
++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
++ buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
++ dev->blocks_in_checkpt);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
++ buf += sprintf(buf, "passive_gc_count..... %u\n",
++ dev->passive_gc_count);
++ buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
++ dev->oldest_dirty_gc_count);
++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
++ buf += sprintf(buf, "n_retried_writes..... %u\n",
++ dev->n_retried_writes);
++ buf += sprintf(buf, "n_retired_blocks..... %u\n",
++ dev->n_retired_blocks);
++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
++ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
++ dev->n_tags_ecc_fixed);
++ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
++ dev->n_tags_ecc_unfixed);
++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
++ buf += sprintf(buf, "n_unlinked_files..... %u\n",
++ dev->n_unlinked_files);
++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
++ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
++ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
++
++ 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 dev_list.
++ * 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,
++ "Multi-version YAFFS built:" __DATE__ " " __TIME__
++ "\n");
++ else if (step == 1)
++ buf += sprintf(buf, "\n");
++ else {
++ step -= 2;
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (n < (step & ~1)) {
++ n += 2;
++ continue;
++ }
++ if ((step & 1) == 0) {
++ buf +=
++ sprintf(buf, "\nDevice %d \"%s\"\n", n,
++ dev->param.name);
++ buf = yaffs_dump_dev_part0(buf, dev);
++ } else {
++ buf = yaffs_dump_dev_part1(buf, dev);
++ }
++
++ break;
++ }
++ mutex_unlock(&yaffs_context_lock);
++ }
++
++ 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},
++ {"background", YAFFS_TRACE_BACKGROUND},
++ {"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},
++ {"lock", YAFFS_TRACE_LOCK},
++ {"mtd", YAFFS_TRACE_MTD},
++ {"nandaccess", YAFFS_TRACE_NANDACCESS},
++ {"os", YAFFS_TRACE_OS},
++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++ {"scan", YAFFS_TRACE_SCAN},
++ {"mount", YAFFS_TRACE_MOUNT},
++ {"tracing", YAFFS_TRACE_TRACING},
++ {"sync", YAFFS_TRACE_SYNC},
++ {"write", YAFFS_TRACE_WRITE},
++ {"verify", YAFFS_TRACE_VERIFY},
++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
++ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
++ {"all", 0xffffffff},
++ {"none", 0},
++ {NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(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_trace_mask;
++
++ 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_trace_mask = rg | YAFFS_TRACE_ALWAYS;
++
++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
++
++ 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(KERN_DEBUG "%c%s\n", flag,
++ mask_flags[i].mask_name);
++ }
++ }
++
++ return count;
++}
++
++/* Debug strings are of the form:
++ * .bnnn print info on block n
++ * .cobjn,chunkn print nand chunk id for objn:chunkn
++ */
++
++static int yaffs_proc_debug_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++
++ char str[100];
++ char *p0;
++ char *p1;
++ long p1_val;
++ long p0_val;
++ char cmd;
++ struct list_head *item;
++
++ memset(str, 0, sizeof(str));
++ memcpy(str, buf, min(count, sizeof(str) -1));
++
++ cmd = str[1];
++
++ p0 = str + 2;
++
++ p1 = p0;
++
++ while (*p1 && *p1 != ',') {
++ p1++;
++ }
++ *p1 = '\0';
++ p1++;
++
++ p0_val = simple_strtol(p0, NULL, 0);
++ p1_val = simple_strtol(p1, NULL, 0);
++
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (cmd == 'b') {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev,p0_val);
++
++ if(bi) {
++ printk("Block %d: state %d, retire %d, use %d, seq %d\n",
++ (int)p0_val, bi->block_state,
++ bi->needs_retiring, bi->pages_in_use,
++ bi->seq_number);
++ }
++ } else if (cmd == 'c') {
++ struct yaffs_obj *obj;
++ int nand_chunk;
++
++ obj = yaffs_find_by_number(dev, p0_val);
++ if (!obj)
++ printk("No obj %d\n", (int)p0_val);
++ else {
++ if(p1_val == 0)
++ nand_chunk = obj->hdr_chunk;
++ else
++ nand_chunk =
++ yaffs_find_chunk_in_file(obj,
++ p1_val, NULL);
++ printk("Nand chunk for %d:%d is %d\n",
++ (int)p0_val, (int)p1_val, nand_chunk);
++ }
++ }
++ }
++
++ mutex_unlock(&yaffs_context_lock);
++
++ return count;
++}
++
++static int yaffs_proc_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ if (buf[0] == '.')
++ return yaffs_proc_debug_write(file, buf, count, data);
++ return yaffs_proc_write_trace_options(file, buf, count, data);
++}
++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
++
++/* 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[] = {
++ {&yaffs_fs_type, 0},
++ {&yaffs2_fs_type, 0},
++ {NULL, 0}
++};
++
++static int __init init_yaffs_fs(void)
++{
++ int error = 0;
++ struct file_system_to_install *fsinst;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " Installing.");
++
++ mutex_init(&yaffs_context_lock);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ /* Install the proc_fs entries */
++ my_proc_entry = create_proc_entry("yaffs",
++ S_IRUGO | S_IFREG, YPROC_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;
++ }
++#endif
++
++ /* 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;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " removing.");
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ remove_proc_entry("yaffs", YPROC_ROOT);
++#endif
++
++ 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-2011");
++MODULE_LICENSE("GPL");
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.13.11/fs/yaffs2/yaffs_yaffs1.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_yaffs1.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,422 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_yaffs1.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++#include "yaffs_attribs.h"
++
++int yaffs1_scan(struct yaffs_dev *dev)
++{
++ struct yaffs_ext_tags tags;
++ int blk;
++ int result;
++ int chunk;
++ int c;
++ int deleted;
++ enum yaffs_block_state state;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int alloc_failed = 0;
++ struct yaffs_shadow_fixer *shadow_fixers = NULL;
++ u8 *chunk_data;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs1_scan starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, state, seq_number);
++
++ if (state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ }
++ bi++;
++ }
++
++ /* For each block.... */
++ for (blk = dev->internal_start_block;
++ !alloc_failed && blk <= dev->internal_end_block; blk++) {
++
++ cond_resched();
++
++ bi = yaffs_get_block_info(dev, blk);
++ state = bi->block_state;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ for (c = 0;
++ !alloc_failed && c < dev->param.chunks_per_block &&
++ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
++ /* Read the tags and decide what to do */
++ chunk = blk * dev->param.chunks_per_block + c;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
++ tags.is_deleted) {
++ /* YAFFS1 only...
++ * A deleted chunk
++ */
++ deleted++;
++ dev->n_free_chunks++;
++ } else if (!tags.chunk_used) {
++ /* An unassigned chunk in the block
++ * This means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (c == 0) {
++ /* We're looking at the first chunk in
++ *the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ /* this is the block being allocated */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, c);
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = c;
++ dev->alloc_block_finder = blk;
++
++ }
++
++ dev->n_free_chunks +=
++ (dev->param.chunks_per_block - c);
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ unsigned int endpos;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ /* PutChunkIntoFile checks for a clash
++ * (two data chunks with the same chunk_id).
++ */
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in) {
++ if (!yaffs_put_chunk_in_file
++ (in, tags.chunk_id, chunk, 1))
++ alloc_failed = 1;
++ }
++
++ endpos =
++ (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk +
++ tags.n_bytes;
++ if (in &&
++ in->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE &&
++ in->variant.file_variant.scanned_size <
++ endpos) {
++ in->variant.file_variant.scanned_size =
++ endpos;
++ if (!dev->param.use_header_file_size) {
++ in->variant.
++ file_variant.file_size =
++ in->variant.
++ file_variant.scanned_size;
++ }
++
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Make the object
++ */
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ in = yaffs_find_by_number(dev, tags.obj_id);
++ if (in && in->variant_type != oh->type) {
++ /* This should not happen, but somehow
++ * Wev'e ended up with an obj_id that
++ * has been reused but not yet deleted,
++ * and worse still it has changed type.
++ * Delete the old object.
++ */
++
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ oh->type);
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in && oh->shadows_obj > 0) {
++
++ struct yaffs_shadow_fixer *fixer;
++ fixer =
++ kmalloc(sizeof
++ (struct yaffs_shadow_fixer),
++ GFP_NOFS);
++ if (fixer) {
++ fixer->next = shadow_fixers;
++ shadow_fixers = fixer;
++ fixer->obj_id = tags.obj_id;
++ fixer->shadowed_id =
++ oh->shadows_obj;
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Shadow fixer: %d shadows %d",
++ fixer->obj_id,
++ fixer->shadowed_id);
++
++ }
++
++ }
++
++ if (in && in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate and need to
++ * resolve it. */
++
++ unsigned existing_serial = in->serial;
++ unsigned new_serial =
++ tags.serial_number;
++
++ if (((existing_serial + 1) & 3) ==
++ new_serial) {
++ /* Use new one - destroy the
++ * exisiting one */
++ yaffs_chunk_del(dev,
++ in->hdr_chunk,
++ 1, __LINE__);
++ in->valid = 0;
++ } else {
++ /* Use existing - destroy
++ * this one. */
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++ }
++ }
++
++ if (in && !in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ } else if (in && !in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ in->dirty = 0;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (!parent)
++ alloc_failed = 1;
++ if (parent && parent->variant_type ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.
++ children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, a problem....
++ * We're trying to use a
++ * non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (dev->param.
++ use_header_file_size)
++ in->variant.
++ file_variant.file_size
++ = yaffs_oh_to_size(oh);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.
++ hardlink_variant.equiv_id =
++ oh->equiv_id;
++ list_add(&in->hard_links,
++ &hard_list);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.
++ alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.
++ symlink_variant.alias)
++ alloc_failed = 1;
++ break;
++ }
++ }
++ }
++ }
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning,
++ * then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ /* If the block was partially allocated then
++ * treat it as fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ bi->block_state = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ yaffs_block_became_dirty(dev, blk);
++ }
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add
++ * these hardlinks.
++ */
++
++ yaffs_link_fixup(dev, &hard_list);
++
++ /*
++ * Fix up any shadowed objects.
++ * There should not be more than one of these.
++ */
++ {
++ struct yaffs_shadow_fixer *fixer;
++ struct yaffs_obj *obj;
++
++ while (shadow_fixers) {
++ fixer = shadow_fixers;
++ shadow_fixers = fixer->next;
++ /* Complete the rename transaction by deleting the
++ * shadowed object then setting the object header
++ to unshadowed.
++ */
++ obj = yaffs_find_by_number(dev, fixer->shadowed_id);
++ if (obj)
++ yaffs_del_obj(obj);
++
++ obj = yaffs_find_by_number(dev, fixer->obj_id);
++
++ if (obj)
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ kfree(fixer);
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.13.11/fs/yaffs2/yaffs_yaffs1.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_yaffs1.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS1_H__
++#define __YAFFS_YAFFS1_H__
++
++#include "yaffs_guts.h"
++int yaffs1_scan(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.13.11/fs/yaffs2/yaffs_yaffs2.c
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_yaffs2.c 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,1534 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_checkptrw.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_verify.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/*
++ * Checkpoints are really no benefit on very small partitions.
++ *
++ * To save space on small partitions don't bother with checkpoints unless
++ * the partition is at least this big.
++ */
++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
++#define YAFFS_SMALL_HOLE_THRESHOLD 4
++
++/*
++ * Oldest Dirty Sequence Number handling.
++ */
++
++/* yaffs_calc_oldest_dirty_seq()
++ * yaffs2_find_oldest_dirty_seq()
++ * Calculate the oldest dirty sequence number if we don't know it.
++ */
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ int i;
++ unsigned seq;
++ unsigned block_no = 0;
++ struct yaffs_block_info *b;
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ /* Find the oldest dirty sequence number. */
++ seq = dev->seq_number + 1;
++ b = dev->block_info;
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
++ (b->pages_in_use - b->soft_del_pages) <
++ dev->param.chunks_per_block &&
++ b->seq_number < seq) {
++ seq = b->seq_number;
++ block_no = i;
++ }
++ b++;
++ }
++
++ if (block_no) {
++ dev->oldest_dirty_seq = seq;
++ dev->oldest_dirty_block = block_no;
++ }
++}
++
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->oldest_dirty_seq)
++ yaffs_calc_oldest_dirty_seq(dev);
++}
++
++/*
++ * yaffs_clear_oldest_dirty_seq()
++ * Called when a block is erased or marked bad. (ie. when its seq_number
++ * becomes invalid). If the value matches the oldest then we clear
++ * dev->oldest_dirty_seq to force its recomputation.
++ */
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++ }
++}
++
++/*
++ * yaffs2_update_oldest_dirty_seq()
++ * Update the oldest dirty sequence number whenever we dirty a block.
++ * Only do this if the oldest_dirty_seq is actually being tracked.
++ */
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (dev->oldest_dirty_seq) {
++ if (dev->oldest_dirty_seq > bi->seq_number) {
++ dev->oldest_dirty_seq = bi->seq_number;
++ dev->oldest_dirty_block = block_no;
++ }
++ }
++}
++
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return 1; /* disqualification only applies to yaffs2. */
++
++ if (!bi->has_shrink_hdr)
++ return 1; /* can gc */
++
++ yaffs2_find_oldest_dirty_seq(dev);
++
++ /* Can't do gc of this block if there are any blocks older than this
++ * one that have discarded pages.
++ */
++ return (bi->seq_number <= dev->oldest_dirty_seq);
++}
++
++/*
++ * yaffs2_find_refresh_block()
++ * periodically finds the oldest full block by sequence number for refreshing.
++ * Only for yaffs2.
++ */
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
++{
++ u32 b;
++ u32 oldest = 0;
++ u32 oldest_seq = 0;
++ struct yaffs_block_info *bi;
++
++ if (!dev->param.is_yaffs2)
++ return oldest;
++
++ /*
++ * If refresh period < 10 then refreshing is disabled.
++ */
++ if (dev->param.refresh_period < 10)
++ return oldest;
++
++ /*
++ * Fix broken values.
++ */
++ if (dev->refresh_skip > dev->param.refresh_period)
++ dev->refresh_skip = dev->param.refresh_period;
++
++ if (dev->refresh_skip > 0)
++ return oldest;
++
++ /*
++ * Refresh skip is now zero.
++ * We'll do a refresh this time around....
++ * Update the refresh skip and find the oldest block.
++ */
++ dev->refresh_skip = dev->param.refresh_period;
++ dev->refresh_count++;
++ bi = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++
++ if (oldest < 1 || bi->seq_number < oldest_seq) {
++ oldest = b;
++ oldest_seq = bi->seq_number;
++ }
++ }
++ bi++;
++ }
++
++ if (oldest > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC refresh count %d selected block %d with seq_number %d",
++ dev->refresh_count, oldest, oldest_seq);
++ }
++
++ return oldest;
++}
++
++int yaffs2_checkpt_required(struct yaffs_dev *dev)
++{
++ int nblocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ return !dev->param.skip_checkpt_wr &&
++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
++}
++
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
++{
++ int retval;
++ int n_bytes = 0;
++ int n_blocks;
++ int dev_blocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
++ /* Not a valid value so recalculate */
++ dev_blocks = dev->param.end_block - dev->param.start_block + 1;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(struct yaffs_checkpt_dev);
++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
++ n_bytes += dev_blocks * dev->chunk_bit_stride;
++ n_bytes +=
++ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
++ dev->n_obj;
++ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(u32); /* checksum */
++
++ /* Round up and add 2 blocks to allow for some bad blocks,
++ * so add 3 */
++
++ n_blocks =
++ (n_bytes /
++ (dev->data_bytes_per_chunk *
++ dev->param.chunks_per_block)) + 3;
++
++ dev->checkpoint_blocks_required = n_blocks;
++ }
++
++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
++ if (retval < 0)
++ retval = 0;
++ return retval;
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++
++ memset(&cp, 0, sizeof(cp));
++
++ cp.struct_type = sizeof(cp);
++ cp.magic = YAFFS_MAGIC;
++ cp.version = YAFFS_CHECKPOINT_VERSION;
++ cp.head = (head) ? 1 : 0;
++
++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok)
++ ok = (cp.struct_type == sizeof(cp)) &&
++ (cp.magic == YAFFS_MAGIC) &&
++ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++ (cp.head == ((head) ? 1 : 0));
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
++ struct yaffs_dev *dev)
++{
++ cp->n_erased_blocks = dev->n_erased_blocks;
++ cp->alloc_block = dev->alloc_block;
++ cp->alloc_page = dev->alloc_page;
++ cp->n_free_chunks = dev->n_free_chunks;
++
++ cp->n_deleted_files = dev->n_deleted_files;
++ cp->n_unlinked_files = dev->n_unlinked_files;
++ cp->n_bg_deletions = dev->n_bg_deletions;
++ cp->seq_number = dev->seq_number;
++
++}
++
++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
++ struct yaffs_checkpt_dev *cp)
++{
++ dev->n_erased_blocks = cp->n_erased_blocks;
++ dev->alloc_block = cp->alloc_block;
++ dev->alloc_page = cp->alloc_page;
++ dev->n_free_chunks = cp->n_free_chunks;
++
++ dev->n_deleted_files = cp->n_deleted_files;
++ dev->n_unlinked_files = cp->n_unlinked_files;
++ dev->n_bg_deletions = cp->n_bg_deletions;
++ dev->seq_number = cp->seq_number;
++}
++
++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ int ok;
++
++ /* Write device runtime values */
++ yaffs2_dev_to_checkpt_dev(&cp, dev);
++ cp.struct_type = sizeof(cp);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ /* Write block info */
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
++ if (!ok)
++ return 0;
++
++ /* Write chunk bits */
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks =
++ (dev->internal_end_block - dev->internal_start_block + 1);
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ if (cp.struct_type != sizeof(cp))
++ return 0;
++
++ yaffs_checkpt_dev_to_dev(dev, &cp);
++
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++
++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
++
++ if (!ok)
++ return 0;
++
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++
++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
++ struct yaffs_obj *obj)
++{
++ cp->obj_id = obj->obj_id;
++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
++ cp->hdr_chunk = obj->hdr_chunk;
++ cp->variant_type = obj->variant_type;
++ cp->deleted = obj->deleted;
++ cp->soft_del = obj->soft_del;
++ cp->unlinked = obj->unlinked;
++ cp->fake = obj->fake;
++ cp->rename_allowed = obj->rename_allowed;
++ cp->unlink_allowed = obj->unlink_allowed;
++ cp->serial = obj->serial;
++ cp->n_data_chunks = obj->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
++}
++
++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
++ struct yaffs_checkpt_obj *cp)
++{
++ struct yaffs_obj *parent;
++
++ if (obj->variant_type != cp->variant_type) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
++ cp->obj_id, cp->variant_type, cp->hdr_chunk,
++ obj->variant_type);
++ return 0;
++ }
++
++ obj->obj_id = cp->obj_id;
++
++ if (cp->parent_id)
++ parent = yaffs_find_or_create_by_number(obj->my_dev,
++ cp->parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ else
++ parent = NULL;
++
++ if (parent) {
++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
++ cp->obj_id, cp->parent_id,
++ cp->variant_type, cp->hdr_chunk,
++ parent->variant_type);
++ return 0;
++ }
++ yaffs_add_obj_to_dir(parent, obj);
++ }
++
++ obj->hdr_chunk = cp->hdr_chunk;
++ obj->variant_type = cp->variant_type;
++ obj->deleted = cp->deleted;
++ obj->soft_del = cp->soft_del;
++ obj->unlinked = cp->unlinked;
++ obj->fake = cp->fake;
++ obj->rename_allowed = cp->rename_allowed;
++ obj->unlink_allowed = cp->unlink_allowed;
++ obj->serial = cp->serial;
++ obj->n_data_chunks = cp->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
++
++ if (obj->hdr_chunk > 0)
++ obj->lazy_loaded = 1;
++ return 1;
++}
++
++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
++ struct yaffs_tnode *tn, u32 level,
++ int chunk_offset)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++ int ok = 1;
++ u32 base_offset;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (!tn->internal[i])
++ continue;
++ ok = yaffs2_checkpt_tnode_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS) + i);
++ }
++ return ok;
++ }
++
++ /* Level 0 tnode */
++ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
++ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
++ sizeof(base_offset));
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++
++ return ok;
++}
++
++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 end_marker = ~0;
++ int ok = 1;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return ok;
++
++ ok = yaffs2_checkpt_tnode_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.file_variant.
++ top_level, 0);
++ if (ok)
++ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
++ sizeof(end_marker)) == sizeof(end_marker));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 base_chunk;
++ int ok = 1;
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
++ struct yaffs_tnode *tn;
++ int nread = 0;
++
++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
++ sizeof(base_chunk));
++
++ while (ok && (~base_chunk)) {
++ nread++;
++ /* Read level 0 tnode */
++
++ tn = yaffs_get_tnode(dev);
++ if (tn)
++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++ else
++ ok = 0;
++
++ if (tn && ok)
++ ok = yaffs_add_find_tnode_0(dev,
++ file_stuct_ptr,
++ base_chunk, tn) ? 1 : 0;
++
++ if (ok)
++ ok = (yaffs2_checkpt_rd
++ (dev, &base_chunk,
++ sizeof(base_chunk)) == sizeof(base_chunk));
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read tnodes %d records, last %d. ok %d",
++ nread, base_chunk, ok);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int i;
++ int ok = 1;
++ struct list_head *lh;
++
++ /* Iterate through the objects in each hash entry,
++ * dumping them to the checkpointing stream.
++ */
++
++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ if (!obj->defered_free) {
++ yaffs2_obj_checkpt_obj(&cp, obj);
++ cp.struct_type = sizeof(cp);
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
++ cp.obj_id, cp.parent_id,
++ cp.variant_type, cp.hdr_chunk, obj);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp,
++ sizeof(cp)) == sizeof(cp));
++
++ if (ok &&
++ obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE)
++ ok = yaffs2_wr_checkpt_tnodes(obj);
++ }
++ }
++ }
++
++ /* Dump end of list */
++ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
++ cp.struct_type = sizeof(cp);
++
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int ok = 1;
++ int done = 0;
++ LIST_HEAD(hard_list);
++
++
++ while (ok && !done) {
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (cp.struct_type != sizeof(cp)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "struct size %d instead of %d ok %d",
++ cp.struct_type, (int)sizeof(cp), ok);
++ ok = 0;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read object %d parent %d type %d chunk %d ",
++ cp.obj_id, cp.parent_id, cp.variant_type,
++ cp.hdr_chunk);
++
++ if (ok && cp.obj_id == ~0) {
++ done = 1;
++ } else if (ok) {
++ obj =
++ yaffs_find_or_create_by_number(dev, cp.obj_id,
++ cp.variant_type);
++ if (obj) {
++ ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
++ if (!ok)
++ break;
++ if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs2_rd_checkpt_tnodes(obj);
++ } else if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_HARDLINK) {
++ list_add(&obj->hard_links, &hard_list);
++ }
++ } else {
++ ok = 0;
++ }
++ }
++ }
++
++ if (ok)
++ yaffs_link_fixup(dev, &hard_list);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum);
++
++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
++ sizeof(checkpt_sum));
++
++ if (!ok)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum0;
++ u32 checkpt_sum1;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
++
++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
++ sizeof(checkpt_sum1));
++
++ if (!ok)
++ return 0;
++
++ if (checkpt_sum0 != checkpt_sum1)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!yaffs2_checkpt_required(dev)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint write");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 1);
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint device");
++ ok = yaffs2_wr_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint objects");
++ ok = yaffs2_wr_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok)
++ ok = yaffs2_wr_checkpt_sum(dev);
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return dev->is_checkpointed;
++}
++
++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!dev->param.is_yaffs2)
++ ok = 0;
++
++ if (ok && dev->param.skip_checkpt_rd) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint read");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint device");
++ ok = yaffs2_rd_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint objects");
++ ok = yaffs2_rd_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok) {
++ ok = yaffs2_rd_checkpt_sum(dev);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint checksum %d", ok);
++ }
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return ok ? 1 : 0;
++}
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
++{
++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
++ dev->is_checkpointed = 0;
++ yaffs2_checkpt_invalidate_stream(dev);
++ }
++ if (dev->param.sb_dirty_fn)
++ dev->param.sb_dirty_fn(dev);
++}
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "save entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++
++ if (!dev->is_checkpointed) {
++ yaffs2_checkpt_invalidate(dev);
++ yaffs2_wr_checkpt_data(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++ "save exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return dev->is_checkpointed;
++}
++
++int yaffs2_checkpt_restore(struct yaffs_dev *dev)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ retval = yaffs2_rd_checkpt_data(dev);
++
++ if (dev->is_checkpointed) {
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return retval;
++}
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
++{
++ /* if new_size > old_file_size.
++ * We're going to be writing a hole.
++ * If the hole is small then write zeros otherwise write a start
++ * of hole marker.
++ */
++ loff_t old_file_size;
++ loff_t increase;
++ int small_hole;
++ int result = YAFFS_OK;
++ struct yaffs_dev *dev = NULL;
++ u8 *local_buffer = NULL;
++ int small_increase_ok = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ dev = obj->my_dev;
++
++ /* Bail out if not yaffs2 mode */
++ if (!dev->param.is_yaffs2)
++ return YAFFS_OK;
++
++ old_file_size = obj->variant.file_variant.file_size;
++
++ if (new_size <= old_file_size)
++ return YAFFS_OK;
++
++ increase = new_size - old_file_size;
++
++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
++ small_hole = 1;
++ else
++ small_hole = 0;
++
++ if (small_hole)
++ local_buffer = yaffs_get_temp_buffer(dev);
++
++ if (local_buffer) {
++ /* fill hole with zero bytes */
++ loff_t pos = old_file_size;
++ int this_write;
++ int written;
++ memset(local_buffer, 0, dev->data_bytes_per_chunk);
++ small_increase_ok = 1;
++
++ while (increase > 0 && small_increase_ok) {
++ this_write = increase;
++ if (this_write > dev->data_bytes_per_chunk)
++ this_write = dev->data_bytes_per_chunk;
++ written =
++ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
++ 0);
++ if (written == this_write) {
++ pos += this_write;
++ increase -= this_write;
++ } else {
++ small_increase_ok = 0;
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++
++ /* If out of space then reverse any chunks we've added */
++ if (!small_increase_ok)
++ yaffs_resize_file_down(obj, old_file_size);
++ }
++
++ if (!small_increase_ok &&
++ obj->parent &&
++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
++ /* Write a hole start header with the old file size */
++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
++ }
++
++ return result;
++}
++
++struct yaffs_block_index {
++ int seq;
++ int block;
++};
++
++static int yaffs2_ybicmp(const void *a, const void *b)
++{
++ int aseq = ((struct yaffs_block_index *)a)->seq;
++ int bseq = ((struct yaffs_block_index *)b)->seq;
++ int ablock = ((struct yaffs_block_index *)a)->block;
++ int bblock = ((struct yaffs_block_index *)b)->block;
++
++ if (aseq == bseq)
++ return ablock - bblock;
++
++ return aseq - bseq;
++}
++
++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int blk, int chunk_in_block,
++ int *found_chunks,
++ u8 *chunk_data,
++ struct list_head *hard_list,
++ int summary_available)
++{
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int equiv_id;
++ loff_t file_size;
++ int is_shrink;
++ int is_unlinked;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++ int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
++ struct yaffs_file_var *file_var;
++ struct yaffs_hardlink_var *hl_var;
++ struct yaffs_symlink_var *sl_var;
++
++ if (summary_available) {
++ result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
++ tags.seq_number = bi->seq_number;
++ }
++
++ if (!summary_available || tags.obj_id == 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
++ dev->tags_used++;
++ } else {
++ dev->summary_used++;
++ }
++
++ /* Let's have a good look at this chunk... */
++
++ if (!tags.chunk_used) {
++ /* An unassigned chunk in the block.
++ * If there are used chunks after this one, then
++ * it is a chunk that was skipped due to failing
++ * the erased check. Just skip it so that it can
++ * be deleted.
++ * But, more typically, We get here when this is
++ * an unallocated chunk and his means that
++ * either the block is empty or this is the one
++ * being allocated from
++ */
++
++ if (*found_chunks) {
++ /* This is a chunk that was skipped due
++ * to failing the erased check */
++ } else if (chunk_in_block == 0) {
++ /* We're looking at the first chunk in
++ * the block so the block is unused */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ if (dev->seq_number == bi->seq_number) {
++ /* Allocating from this block*/
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, chunk_in_block);
++
++ bi->block_state =
++ YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = chunk_in_block;
++ dev->alloc_block_finder = blk;
++ } else {
++ /* This is a partially written block
++ * that is not the current
++ * allocation block.
++ */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Partially written block %d detected. gc will fix this.",
++ blk);
++ }
++ }
++ }
++
++ dev->n_free_chunks++;
++
++ } else if (tags.ecc_result ==
++ YAFFS_ECC_RESULT_UNFIXED) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Unfixed ECC in chunk(%d:%d), chunk ignored",
++ blk, chunk_in_block);
++ dev->n_free_chunks++;
++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
++ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
++ tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
++ (tags.chunk_id > 0 &&
++ tags.n_bytes > dev->data_bytes_per_chunk) ||
++ tags.seq_number != bi->seq_number) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
++ blk, chunk_in_block, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++ dev->n_free_chunks++;
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ loff_t endpos;
++ loff_t chunk_base = (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk;
++
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!in)
++ /* Out of memory */
++ alloc_failed = 1;
++
++ if (in &&
++ in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
++ chunk_base < in->variant.file_variant.shrink_size) {
++ /* This has not been invalidated by
++ * a resize */
++ if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
++ chunk, -1))
++ alloc_failed = 1;
++
++ /* File size is calculated by looking at
++ * the data chunks if we have not
++ * seen an object header yet.
++ * Stop this practice once we find an
++ * object header.
++ */
++ endpos = chunk_base + tags.n_bytes;
++
++ if (!in->valid &&
++ in->variant.file_variant.scanned_size < endpos) {
++ in->variant.file_variant.
++ scanned_size = endpos;
++ in->variant.file_variant.
++ file_size = endpos;
++ }
++ } else if (in) {
++ /* This chunk has been invalidated by a
++ * resize, or a past file deletion
++ * so delete the chunk*/
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make
++ * the object
++ */
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ oh = NULL;
++ in = NULL;
++
++ if (tags.extra_available) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ tags.extra_obj_type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ if (!in ||
++ (!in->valid && dev->param.disable_lazy_load) ||
++ tags.extra_shadows ||
++ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
++
++ /* If we don't have valid info then we
++ * need to read the chunk
++ * TODO In future we can probably defer
++ * reading the chunk and living with
++ * invalid data until needed.
++ */
++
++ result = yaffs_rd_chunk_tags_nand(dev,
++ chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ if (dev->param.inband_tags) {
++ /* Fix up the header if they got
++ * corrupted by inband tags */
++ oh->shadows_obj =
++ oh->inband_shadowed_obj_id;
++ oh->is_shrink =
++ oh->inband_is_shrink;
++ }
++
++ if (!in) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id, oh->type);
++ if (!in)
++ alloc_failed = 1;
++ }
++ }
++
++ if (!in) {
++ /* TODO Hoosterman we have a problem! */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
++ tags.obj_id, chunk);
++ return YAFFS_FAIL;
++ }
++
++ if (in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate that will be
++ * discarded, but we first have to suck
++ * out resize info if it is a file.
++ */
++ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
++ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
++ (tags.extra_available &&
++ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ )) {
++ loff_t this_size = (oh) ?
++ yaffs_oh_to_size(oh) :
++ tags.extra_file_size;
++ u32 parent_obj_id = (oh) ?
++ oh->parent_obj_id :
++ tags.extra_parent_id;
++
++ is_shrink = (oh) ?
++ oh->is_shrink :
++ tags.extra_is_shrink;
++
++ /* If it is deleted (unlinked
++ * at start also means deleted)
++ * we treat the file size as
++ * being zeroed at this point.
++ */
++ if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
++ parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
++ this_size = 0;
++ is_shrink = 1;
++ }
++
++ if (is_shrink &&
++ in->variant.file_variant.shrink_size >
++ this_size)
++ in->variant.file_variant.shrink_size =
++ this_size;
++
++ if (is_shrink)
++ bi->has_shrink_hdr = 1;
++ }
++ /* Use existing - destroy this one. */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++
++ if (!in->valid && in->variant_type !=
++ (oh ? oh->type : tags.extra_obj_type)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
++ oh ? oh->type : tags.extra_obj_type,
++ in->variant_type, tags.obj_id,
++ chunk);
++ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
++ }
++
++ if (!in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++
++ if (oh) {
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->lazy_loaded = 0;
++ } else {
++ in->lazy_loaded = 1;
++ }
++ in->hdr_chunk = chunk;
++
++ } else if (!in->valid) {
++ /* we need to load this info */
++ in->valid = 1;
++ in->hdr_chunk = chunk;
++ if (oh) {
++ in->variant_type = oh->type;
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++
++ if (oh->shadows_obj > 0)
++ yaffs_handle_shadowed_obj(dev,
++ oh->shadows_obj, 1);
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ parent = yaffs_find_or_create_by_number(dev,
++ oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = yaffs_oh_to_size(oh);
++ is_shrink = oh->is_shrink;
++ equiv_id = oh->equiv_id;
++ } else {
++ in->variant_type = tags.extra_obj_type;
++ parent = yaffs_find_or_create_by_number(dev,
++ tags.extra_parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = tags.extra_file_size;
++ is_shrink = tags.extra_is_shrink;
++ equiv_id = tags.extra_equiv_id;
++ in->lazy_loaded = 1;
++ }
++ in->dirty = 0;
++
++ if (!parent)
++ alloc_failed = 1;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ if (parent &&
++ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * Trying to use a non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++ yaffs_add_obj_to_dir(parent, in);
++
++ is_unlinked = (parent == dev->del_dir) ||
++ (parent == dev->unlinked_dir);
++
++ if (is_shrink)
++ /* Mark the block */
++ bi->has_shrink_hdr = 1;
++
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent
++ * object is scanned we put them all in a list.
++ * After scanning is complete, we should have all the
++ * objects, so we run through this list and fix up all
++ * the chains.
++ */
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ file_var = &in->variant.file_variant;
++ if (file_var->scanned_size < file_size) {
++ /* This covers the case where the file
++ * size is greater than the data held.
++ * This will happen if the file is
++ * resized to be larger than its
++ * current data extents.
++ */
++ file_var->file_size = file_size;
++ file_var->scanned_size = file_size;
++ }
++
++ if (file_var->shrink_size > file_size)
++ file_var->shrink_size = file_size;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ hl_var = &in->variant.hardlink_variant;
++ if (!is_unlinked) {
++ hl_var->equiv_id = equiv_id;
++ list_add(&in->hard_links, hard_list);
++ }
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ sl_var = &in->variant.symlink_variant;
++ if (oh) {
++ sl_var->alias =
++ yaffs_clone_str(oh->alias);
++ if (!sl_var->alias)
++ alloc_failed = 1;
++ }
++ break;
++ }
++ }
++ }
++ return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
++}
++
++int yaffs2_scan_backwards(struct yaffs_dev *dev)
++{
++ int blk;
++ int block_iter;
++ int start_iter;
++ int end_iter;
++ int n_to_scan = 0;
++ enum yaffs_block_state state;
++ int c;
++ int deleted;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ u8 *chunk_data;
++ int found_chunks;
++ int alloc_failed = 0;
++ struct yaffs_block_index *block_index = NULL;
++ int alt_block_index = 0;
++ int summary_available;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ block_index =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
++
++ if (!block_index) {
++ block_index =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_index));
++ alt_block_index = 1;
++ }
++
++ if (!block_index) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards() could not allocate block index!"
++ );
++ return YAFFS_FAIL;
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, bi->block_state, seq_number);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ dev->blocks_in_checkpt++;
++
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ } else if (bi->block_state ==
++ YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* Determine the highest sequence number */
++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++ block_index[n_to_scan].seq = seq_number;
++ block_index[n_to_scan].block = blk;
++ n_to_scan++;
++ if (seq_number >= dev->seq_number)
++ dev->seq_number = seq_number;
++ } else {
++ /* TODO: Nasty sequence number! */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Block scanning block %d has bad sequence number %d",
++ blk, seq_number);
++ }
++ }
++ bi++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
++
++ cond_resched();
++
++ /* Sort the blocks by sequence number */
++ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
++ yaffs2_ybicmp, NULL);
++
++ cond_resched();
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "...done");
++
++ /* Now scan the blocks looking at the data. */
++ start_iter = 0;
++ end_iter = n_to_scan - 1;
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
++
++ /* For each block.... backwards */
++ for (block_iter = end_iter;
++ !alloc_failed && block_iter >= start_iter;
++ block_iter--) {
++ /* Cooperative multitasking! This loop can run for so
++ long that watchdog timers expire. */
++ cond_resched();
++
++ /* get the block to scan in the correct order */
++ blk = block_index[block_iter].block;
++ bi = yaffs_get_block_info(dev, blk);
++ deleted = 0;
++
++ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
++
++ /* For each chunk in each block that needs scanning.... */
++ found_chunks = 0;
++ if (summary_available)
++ c = dev->chunks_per_summary - 1;
++ else
++ c = dev->param.chunks_per_block - 1;
++
++ for (/* c is already initialised */;
++ !alloc_failed && c >= 0 &&
++ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
++ c--) {
++ /* Scan backwards...
++ * Read the tags and decide what to do
++ */
++ if (yaffs2_scan_chunk(dev, bi, blk, c,
++ &found_chunks, chunk_data,
++ &hard_list, summary_available) ==
++ YAFFS_FAIL)
++ alloc_failed = 1;
++ }
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning, then the block
++ * is fully allocated. */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_block_became_dirty(dev, blk);
++ }
++ }
++
++ yaffs_skip_rest_of_block(dev);
++
++ if (alt_block_index)
++ vfree(block_index);
++ else
++ kfree(block_index);
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++ yaffs_link_fixup(dev, &hard_list);
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.13.11/fs/yaffs2/yaffs_yaffs2.h
+--- linux-3.13.11.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yaffs_yaffs2.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS2_H__
++#define __YAFFS_YAFFS2_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi);
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
++int yaffs2_checkpt_required(struct yaffs_dev *dev);
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
++int yaffs2_checkpt_save(struct yaffs_dev *dev);
++int yaffs2_checkpt_restore(struct yaffs_dev *dev);
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
++int yaffs2_scan_backwards(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.13.11.orig/fs/yaffs2/yportenv.h linux-3.13.11/fs/yaffs2/yportenv.h
+--- linux-3.13.11.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.13.11/fs/yaffs2/yportenv.h 2014-05-17 08:34:57.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#ifdef YAFFS_OUT_OF_TREE
++#include "moduleconfig.h"
++#endif
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/xattr.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/sort.h>
++#include <linux/bitops.h>
++
++/* These type wrappings are used to support Unicode names in WinCE. */
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#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 compile_time_assertion(assertion) \
++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++
++#define yaffs_printf(msk, fmt, ...) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
++
++#define yaffs_trace(msk, fmt, ...) do { \
++ if (yaffs_trace_mask & (msk)) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
++} while (0)
++
++
++#endif
diff --git a/target/linux/patches/3.4.87/gemalto.patch b/target/linux/patches/3.4.87/gemalto.patch
deleted file mode 100644
index 65f7af1d7..000000000
--- a/target/linux/patches/3.4.87/gemalto.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -Nur linux-2.6.36.orig/drivers/tty/serial/8250/serial_cs.c linux-2.6.36/drivers/serial/8250/serial_cs.c
---- linux-2.6.36.orig/drivers/tty/serial/8250/serial_cs.c 2010-10-20 22:30:22.000000000 +0200
-+++ linux-2.6.36/drivers/tty/serial/8250/serial_cs.c 2010-12-13 23:03:40.000000000 +0100
-@@ -794,6 +794,7 @@
- PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
- PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
- PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
-+ PCMCIA_DEVICE_MANF_CARD(0x0157, 0x0100), /* Gemalto SCR */
- PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
- PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
- PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
diff --git a/target/linux/patches/3.4.87/lemote-rfkill.patch b/target/linux/patches/3.4.87/lemote-rfkill.patch
deleted file mode 100644
index a61488434..000000000
--- a/target/linux/patches/3.4.87/lemote-rfkill.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-diff -Nur linux-3.3.orig/drivers/net/wireless/rtl818x/rtl8187/rfkill.c linux-3.3/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
---- linux-3.3.orig/drivers/net/wireless/rtl818x/rtl8187/rfkill.c 2012-03-19 00:15:34.000000000 +0100
-+++ linux-3.3/drivers/net/wireless/rtl818x/rtl8187/rfkill.c 2012-03-27 23:29:46.000000000 +0200
-@@ -22,6 +22,9 @@
-
- static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
- {
-+#ifdef CONFIG_LEMOTE_MACH2F
-+ return 1;
-+#else
- u8 gpio;
-
- gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
-@@ -29,6 +32,7 @@
- gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
-
- return gpio & priv->rfkill_mask;
-+#endif
- }
-
- void rtl8187_rfkill_init(struct ieee80211_hw *hw)
diff --git a/target/linux/patches/3.4.87/non-static.patch b/target/linux/patches/3.4.87/non-static.patch
deleted file mode 100644
index a967703d0..000000000
--- a/target/linux/patches/3.4.87/non-static.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-diff -Nur linux-2.6.39-rc6.orig/fs/namei.c linux-2.6.39-rc6/fs/namei.c
---- linux-2.6.39-rc6.orig/fs/namei.c 2011-05-04 04:59:13.000000000 +0200
-+++ linux-2.6.39-rc6/fs/namei.c 2011-05-05 11:30:14.000000000 +0200
-@@ -1769,7 +1769,7 @@
- * needs parent already locked. Doesn't follow mounts.
- * SMP-safe.
- */
--static struct dentry *lookup_hash(struct nameidata *nd)
-+struct dentry *lookup_hash(struct nameidata *nd)
- {
- return __lookup_hash(&nd->last, nd->path.dentry, nd);
- }
-diff -Nur linux-2.6.39-rc6.orig/fs/splice.c linux-2.6.39-rc6/fs/splice.c
---- linux-2.6.39-rc6.orig/fs/splice.c 2011-05-04 04:59:13.000000000 +0200
-+++ linux-2.6.39-rc6/fs/splice.c 2011-05-05 11:31:04.000000000 +0200
-@@ -1081,7 +1081,7 @@
- /*
- * Attempt to initiate a splice from pipe to file.
- */
--static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
-+long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
- loff_t *ppos, size_t len, unsigned int flags)
- {
- ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
-@@ -1109,7 +1109,7 @@
- /*
- * Attempt to initiate a splice from a file to a pipe.
- */
--static long do_splice_to(struct file *in, loff_t *ppos,
-+long do_splice_to(struct file *in, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags)
- {
diff --git a/target/linux/patches/3.4.87/uuid.patch b/target/linux/patches/3.4.87/uuid.patch
deleted file mode 100644
index ca23accdf..000000000
--- a/target/linux/patches/3.4.87/uuid.patch
+++ /dev/null
@@ -1,263 +0,0 @@
-diff -Nur linux-3.4.2.orig/block/genhd.c linux-3.4.2/block/genhd.c
---- linux-3.4.2.orig/block/genhd.c 2012-06-09 17:36:33.000000000 +0200
-+++ linux-3.4.2/block/genhd.c 2012-06-15 18:19:16.000000000 +0200
-@@ -33,7 +33,7 @@
- static DEFINE_MUTEX(ext_devt_mutex);
- static DEFINE_IDR(ext_devt_idr);
-
--static struct device_type disk_type;
-+struct device_type disk_type;
-
- static void disk_alloc_events(struct gendisk *disk);
- static void disk_add_events(struct gendisk *disk);
-@@ -1122,7 +1122,7 @@
- return NULL;
- }
-
--static struct device_type disk_type = {
-+struct device_type disk_type = {
- .name = "disk",
- .groups = disk_attr_groups,
- .release = disk_release,
-diff -Nur linux-3.4.2.orig/init/do_mounts.c linux-3.4.2/init/do_mounts.c
---- linux-3.4.2.orig/init/do_mounts.c 2012-06-09 17:36:33.000000000 +0200
-+++ linux-3.4.2/init/do_mounts.c 2012-06-15 18:20:11.000000000 +0200
-@@ -21,6 +21,7 @@
- #include <linux/nfs_fs_sb.h>
- #include <linux/nfs_mount.h>
-
-+#include "../fs/ext2/ext2.h"
- #include "do_mounts.h"
-
- int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
-@@ -32,6 +33,132 @@
-
- dev_t ROOT_DEV;
-
-+#ifdef CONFIG_EXT2_FS
-+/* support for root=UUID=ce40d6b2-18eb-4a75-aefe-7ddb0995ce63 bootargs */
-+
-+#include <linux/ext2_fs.h>
-+
-+__u8 root_dev_uuid[16];
-+int root_dev_type; /* 0 = normal (/dev/hda1, 0301); 1 = UUID; 3 = bad */
-+
-+/* imported from block/genhd.c after removing its static qualifier */
-+extern struct device_type disk_type;
-+
-+/* helper function */
-+static __u8 __init fromhex(char c)
-+{
-+ if (c >= '0' && c <= '9')
-+ return (c - '0');
-+ c &= ~32;
-+ if (c >= 'A' && c <= 'F')
-+ return (c - 'A' + 10);
-+ return (0xFF);
-+}
-+
-+static void __init parse_uuid(const char *s)
-+{
-+ int i;
-+ __u8 j, k;
-+
-+ if (strlen(s) != 36 || s[8] != '-' || s[13] != '-' ||
-+ s[18] != '-' || s[23] != '-')
-+ goto bad_uuid;
-+ for (i = 0; i < 16; i++) {
-+ if (*s == '-')
-+ ++s;
-+ j = fromhex(*s++);
-+ k = fromhex(*s++);
-+ if (j == 0xFF || k == 0xFF)
-+ goto bad_uuid;
-+ root_dev_uuid[i] = (j << 4) | k;
-+ }
-+ return;
-+ bad_uuid:
-+ /* we cannot panic here, defer */
-+ root_dev_type = 3;
-+}
-+
-+/* from drivers/md/md.c */
-+static void __init initcode_bi_complete(struct bio *bio, int error)
-+{
-+ complete((struct completion*)bio->bi_private);
-+}
-+
-+static int __init initcode_sync_page_read(struct block_device *bdev,
-+ sector_t sector, int size, struct page *page)
-+{
-+ struct bio *bio = bio_alloc(GFP_NOIO, 1);
-+ struct completion event;
-+ int ret, rw = READ;
-+
-+ rw |= REQ_SYNC;
-+
-+ bio->bi_bdev = bdev;
-+ bio->bi_sector = sector;
-+ bio_add_page(bio, page, size, 0);
-+ init_completion(&event);
-+ bio->bi_private = &event;
-+ bio->bi_end_io = initcode_bi_complete;
-+ submit_bio(rw, bio);
-+ wait_for_completion(&event);
-+
-+ ret = test_bit(BIO_UPTODATE, &bio->bi_flags);
-+ bio_put(bio);
-+ /* 0 = failure */
-+ return ret;
-+}
-+
-+/* most of this taken from fs/ext2/super.c */
-+static int __init check_dev(struct gendisk *thedisk, dev_t devt,
-+ int blocksize, struct page *page)
-+{
-+ struct ext2_super_block * es;
-+ struct block_device *bdev;
-+ unsigned long sb_block = 1;
-+ unsigned long logic_sb_block;
-+ unsigned long offset = 0;
-+ int rv = /* not found */ 0;
-+ char bff[22];
-+
-+ bdev = bdget(devt);
-+ if (blkdev_get(bdev, FMODE_READ, NULL)) {
-+ printk(KERN_ERR "VFS: opening block device %s failed!\n",
-+ format_dev_t(bff, devt));
-+ return (0);
-+ }
-+
-+ if (blocksize != BLOCK_SIZE) {
-+ logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
-+ offset = (sb_block*BLOCK_SIZE) % blocksize;
-+ } else {
-+ logic_sb_block = sb_block;
-+ }
-+
-+// printk(KERN_ERR "D: attempting to read %d @%lu from "
-+// "bdev %p devt %08X %s\n", blocksize, logic_sb_block,
-+// bdev, devt, format_dev_t(bff, devt));
-+ if (!initcode_sync_page_read(bdev, logic_sb_block, blocksize, page)) {
-+// printk(KERN_ERR "D: failed!\n");
-+ goto out;
-+ }
-+ es = (struct ext2_super_block *)(((char *)page_address(page)) + offset);
-+ if (le16_to_cpu(es->s_magic) == EXT2_SUPER_MAGIC) {
-+// printk(KERN_ERR "D: has uuid "
-+// "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
-+// es->s_uuid[0], es->s_uuid[1], es->s_uuid[2], es->s_uuid[3],
-+// es->s_uuid[4], es->s_uuid[5], es->s_uuid[6], es->s_uuid[7],
-+// es->s_uuid[8], es->s_uuid[9], es->s_uuid[10], es->s_uuid[11],
-+// es->s_uuid[12], es->s_uuid[13], es->s_uuid[14], es->s_uuid[15]);
-+ if (!memcmp(es->s_uuid, root_dev_uuid, 16))
-+ rv = /* found */ 1;
-+ }
-+// else printk(KERN_ERR "D: bad ext2fs magic\n");
-+ out:
-+ blkdev_put(bdev, FMODE_READ);
-+ return (rv);
-+}
-+#endif /* CONFIG_EXT2_FS for UUID support */
-+
- static int __init load_ramdisk(char *str)
- {
- rd_doload = simple_strtol(str,NULL,0) & 3;
-@@ -256,6 +383,13 @@
- static int __init root_dev_setup(char *line)
- {
- strlcpy(saved_root_name, line, sizeof(saved_root_name));
-+#ifdef CONFIG_EXT2_FS
-+ root_dev_type = 0;
-+ if (!strncmp(line, "UUID=", 5)) {
-+ root_dev_type = 1;
-+ parse_uuid(line + 5);
-+ }
-+#endif /* CONFIG_EXT2_FS for UUID support */
- return 1;
- }
-
-@@ -471,6 +605,83 @@
-
- void __init mount_root(void)
- {
-+#ifdef CONFIG_EXT2_FS
-+ /* UUID support */
-+// printk_all_partitions();
-+ if (root_dev_type == 1) {
-+ int blocksize;
-+
-+ /* from block/genhd.c printk_all_partitions */
-+ struct class_dev_iter iter;
-+ struct device *dev;
-+
-+ /* from drivers/md/md.c */
-+ struct page *sb_page;
-+
-+ if (!(sb_page = alloc_page(GFP_KERNEL))) {
-+ printk(KERN_ERR "VFS: no memory for bio page\n");
-+ goto nomemforbio;
-+ }
-+
-+// printk(KERN_ERR "D: root is: "
-+// "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
-+// root_dev_uuid[0], root_dev_uuid[1], root_dev_uuid[2], root_dev_uuid[3],
-+// root_dev_uuid[4], root_dev_uuid[5], root_dev_uuid[6], root_dev_uuid[7],
-+// root_dev_uuid[8], root_dev_uuid[9], root_dev_uuid[10], root_dev_uuid[11],
-+// root_dev_uuid[12], root_dev_uuid[13], root_dev_uuid[14], root_dev_uuid[15]);
-+ /* from block/genhd.c printk_all_partitions */
-+// printk(KERN_ERR "D: begin iter\n");
-+ class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
-+ while (root_dev_type && (dev = class_dev_iter_next(&iter))) {
-+// char bff[22];
-+ struct gendisk *disk = dev_to_disk(dev);
-+ struct disk_part_iter piter;
-+ struct hd_struct *part;
-+ if (get_capacity(disk) == 0 ||
-+ (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) {
-+// printk(KERN_ERR "D: ignoring\n");
-+ continue;
-+ }
-+ blocksize = queue_logical_block_size(disk->queue);
-+// printk(KERN_ERR "D: gendisk, blocksize %d "
-+// "name '%s' devt %08X %s #part %d\n", blocksize,
-+// disk->disk_name, dev->devt,
-+// format_dev_t(bff, dev->devt),
-+// disk_max_parts(disk));
-+ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
-+ while (root_dev_type && (part = disk_part_iter_next(&piter))) {
-+ /* avoid empty or too small partitions */
-+// printk(KERN_ERR "D: part #%d start %llu "
-+// "nr %llu\n", part->partno,
-+// (__u64)part->start_sect,
-+// (__u64)part->nr_sects);
-+ if (part->nr_sects < 8)
-+ continue;
-+ if (check_dev(disk, MKDEV(MAJOR(dev->devt),
-+ MINOR(dev->devt) + part->partno),
-+ blocksize, sb_page)) {
-+ ROOT_DEV = part_devt(part);
-+// printk(KERN_ERR "D: got match!\n");
-+ // comment out below for debugging
-+ root_dev_type = 0;
-+ }
-+ }
-+ disk_part_iter_exit(&piter);
-+ }
-+// printk(KERN_ERR "D: end iter\n");
-+ class_dev_iter_exit(&iter);
-+ put_page(sb_page);
-+ }
-+ nomemforbio:
-+ if (root_dev_type == 1)
-+ printk(KERN_ERR "VFS: Unable to find root by UUID %s.\n",
-+ saved_root_name + 5);
-+ else if (root_dev_type == 3)
-+ /* execute deferred panic from parse_uuid */
-+ panic("Badly formatted UUID %s was supplied as kernel "
-+ "parameter root", saved_root_name + 5);
-+#endif /* CONFIG_EXT2_FS for UUID support */
-+
- #ifdef CONFIG_ROOT_NFS
- if (ROOT_DEV == Root_NFS) {
- if (mount_nfs_root())
diff --git a/target/linux/patches/3.4.87/wlan-cf.patch b/target/linux/patches/3.4.87/wlan-cf.patch
deleted file mode 100644
index fc20759e2..000000000
--- a/target/linux/patches/3.4.87/wlan-cf.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -Nur linux-2.6.39.orig/drivers/net/wireless/hostap/hostap_cs.c linux-2.6.39/drivers/net/wireless/hostap/hostap_cs.c
---- linux-2.6.39.orig/drivers/net/wireless/hostap/hostap_cs.c 2011-05-19 06:06:34.000000000 +0200
-+++ linux-2.6.39/drivers/net/wireless/hostap/hostap_cs.c 2011-09-12 02:46:26.987984145 +0200
-@@ -623,6 +623,7 @@
- static struct pcmcia_device_id hostap_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
-+ PCMCIA_DEVICE_MANF_CARD(0x0004, 0x2003),
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
- PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
diff --git a/target/linux/patches/3.4.87/zlib-inflate.patch b/target/linux/patches/3.4.87/zlib-inflate.patch
deleted file mode 100644
index 58e1f6d21..000000000
--- a/target/linux/patches/3.4.87/zlib-inflate.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Nur linux-2.6.37.orig/lib/Kconfig linux-2.6.37/lib/Kconfig
---- linux-2.6.37.orig/lib/Kconfig 2011-01-05 01:50:19.000000000 +0100
-+++ linux-2.6.37/lib/Kconfig 2011-03-01 20:10:29.833370667 +0100
-@@ -95,7 +95,7 @@
- # compression support is select'ed if needed
- #
- config ZLIB_INFLATE
-- tristate
-+ boolean
-
- config ZLIB_DEFLATE
- tristate
diff --git a/target/linux/patches/3.4.87/bsd-compatibility.patch b/target/linux/patches/3.4.90/bsd-compatibility.patch
index 9e91a62de..9e91a62de 100644
--- a/target/linux/patches/3.4.87/bsd-compatibility.patch
+++ b/target/linux/patches/3.4.90/bsd-compatibility.patch
diff --git a/target/linux/patches/3.4.87/defaults.patch b/target/linux/patches/3.4.90/defaults.patch
index 58aae610b..58aae610b 100644
--- a/target/linux/patches/3.4.87/defaults.patch
+++ b/target/linux/patches/3.4.90/defaults.patch
diff --git a/target/linux/patches/3.12.18/gemalto.patch b/target/linux/patches/3.4.90/gemalto.patch
index 65f7af1d7..65f7af1d7 100644
--- a/target/linux/patches/3.12.18/gemalto.patch
+++ b/target/linux/patches/3.4.90/gemalto.patch
diff --git a/target/linux/patches/3.12.18/lemote-rfkill.patch b/target/linux/patches/3.4.90/lemote-rfkill.patch
index a61488434..a61488434 100644
--- a/target/linux/patches/3.12.18/lemote-rfkill.patch
+++ b/target/linux/patches/3.4.90/lemote-rfkill.patch
diff --git a/target/linux/patches/3.4.87/mips-error.patch b/target/linux/patches/3.4.90/mips-error.patch
index 800abc80d..800abc80d 100644
--- a/target/linux/patches/3.4.87/mips-error.patch
+++ b/target/linux/patches/3.4.90/mips-error.patch
diff --git a/target/linux/patches/3.4.87/module-alloc-size-check.patch b/target/linux/patches/3.4.90/module-alloc-size-check.patch
index a792ac60a..a792ac60a 100644
--- a/target/linux/patches/3.4.87/module-alloc-size-check.patch
+++ b/target/linux/patches/3.4.90/module-alloc-size-check.patch
diff --git a/target/linux/patches/3.12.18/non-static.patch b/target/linux/patches/3.4.90/non-static.patch
index a967703d0..a967703d0 100644
--- a/target/linux/patches/3.12.18/non-static.patch
+++ b/target/linux/patches/3.4.90/non-static.patch
diff --git a/target/linux/patches/3.4.87/sparc-include.patch b/target/linux/patches/3.4.90/sparc-include.patch
index 2f8ffd061..2f8ffd061 100644
--- a/target/linux/patches/3.4.87/sparc-include.patch
+++ b/target/linux/patches/3.4.90/sparc-include.patch
diff --git a/target/linux/patches/3.4.87/startup.patch b/target/linux/patches/3.4.90/startup.patch
index c26430bcb..c26430bcb 100644
--- a/target/linux/patches/3.4.87/startup.patch
+++ b/target/linux/patches/3.4.90/startup.patch
diff --git a/target/linux/patches/3.4.87/usb-defaults-off.patch b/target/linux/patches/3.4.90/usb-defaults-off.patch
index 31367108a..31367108a 100644
--- a/target/linux/patches/3.4.87/usb-defaults-off.patch
+++ b/target/linux/patches/3.4.90/usb-defaults-off.patch
diff --git a/target/linux/patches/3.12.18/uuid.patch b/target/linux/patches/3.4.90/uuid.patch
index ca23accdf..ca23accdf 100644
--- a/target/linux/patches/3.12.18/uuid.patch
+++ b/target/linux/patches/3.4.90/uuid.patch
diff --git a/target/linux/patches/3.4.87/vga-cons-default-off.patch b/target/linux/patches/3.4.90/vga-cons-default-off.patch
index 178aeeeb9..178aeeeb9 100644
--- a/target/linux/patches/3.4.87/vga-cons-default-off.patch
+++ b/target/linux/patches/3.4.90/vga-cons-default-off.patch
diff --git a/target/linux/patches/3.12.18/wlan-cf.patch b/target/linux/patches/3.4.90/wlan-cf.patch
index fc20759e2..fc20759e2 100644
--- a/target/linux/patches/3.12.18/wlan-cf.patch
+++ b/target/linux/patches/3.4.90/wlan-cf.patch
diff --git a/target/linux/patches/3.4.90/yaffs2.patch b/target/linux/patches/3.4.90/yaffs2.patch
new file mode 100644
index 000000000..44c95915f
--- /dev/null
+++ b/target/linux/patches/3.4.90/yaffs2.patch
@@ -0,0 +1,16550 @@
+diff -Nur linux-3.4.90.orig/fs/Kconfig linux-3.4.90/fs/Kconfig
+--- linux-3.4.90.orig/fs/Kconfig 2014-05-13 14:11:45.000000000 +0200
++++ linux-3.4.90/fs/Kconfig 2014-05-17 15:08:09.000000000 +0200
+@@ -203,6 +203,7 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Nur linux-3.4.90.orig/fs/Makefile linux-3.4.90/fs/Makefile
+--- linux-3.4.90.orig/fs/Makefile 2014-05-13 14:11:45.000000000 +0200
++++ linux-3.4.90/fs/Makefile 2014-05-17 15:09:05.000000000 +0200
+@@ -97,6 +97,7 @@
+ obj-$(CONFIG_UFS_FS) += ufs/
+ obj-$(CONFIG_EFS_FS) += efs/
+ obj-$(CONFIG_JFFS2_FS) += jffs2/
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
+ obj-$(CONFIG_LOGFS) += logfs/
+ obj-$(CONFIG_UBIFS_FS) += ubifs/
+ obj-$(CONFIG_AFFS_FS) += affs/
+diff -Nur linux-3.4.90.orig/fs/yaffs2/Kconfig linux-3.4.90/fs/yaffs2/Kconfig
+--- linux-3.4.90.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/Kconfig 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,171 @@
++#
++# yaffs file system configurations
++#
++
++config YAFFS_FS
++ tristate "yaffs2 file system support"
++ default n
++ depends on MTD_BLOCK
++ select YAFFS_YAFFS1
++ select YAFFS_YAFFS2
++ help
++ yaffs2, or Yet Another Flash File System, is a file 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
++ in yaffs_mtdif1.c.
++
++ 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_TAGS_ECC
++ bool "Disable yaffs from doing ECC on tags by default"
++ depends on YAFFS_FS && YAFFS_YAFFS2
++ default n
++ help
++ This defaults yaffs to using its own ECC calculations on tags instead of
++ just relying on the MTD.
++ This behavior can also be overridden with tags_ecc_on and
++ tags_ecc_off mount options.
++
++ 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_EMPTY_LOST_AND_FOUND
++ bool "Empty lost and found on boot"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is enabled then the contents of lost and found is
++ automatically dumped at mount.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++ bool "Disable yaffs2 block refreshing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then block refreshing is disabled.
++ Block refreshing infrequently refreshes the oldest block in
++ a yaffs2 file system. This mechanism helps to refresh flash to
++ mitigate against data loss. This is particularly useful for MLC.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++ bool "Disable yaffs2 background processing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then background processing is disabled.
++ Background processing makes many foreground activities faster.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BAD_BLOCK_MARKING
++ bool "Disable yaffs2 bad block marking"
++ depends on YAFFS_FS
++ default n
++ help
++ Useful during early flash bring up to prevent problems causing
++ lots of bad block marking.
++
++ If unsure, say N.
++
++config YAFFS_XATTR
++ bool "Enable yaffs2 xattr support"
++ depends on YAFFS_FS
++ default y
++ help
++ If this is set then yaffs2 will provide xattr support.
++ If unsure, say Y.
+diff -Nur linux-3.4.90.orig/fs/yaffs2/Makefile linux-3.4.90/fs/yaffs2/Makefile
+--- linux-3.4.90.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/Makefile 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,18 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
++yaffs-y += yaffs_mtdif.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_summary.o
++yaffs-y += yaffs_verify.o
++
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.c linux-3.4.90/fs/yaffs2/yaffs_allocator.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_allocator.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,357 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++/*
++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
++ * of approx 100 objects that are themn allocated singly.
++ * This is basically a simplified slab allocator.
++ *
++ * We don't use the Linux slab allocator because slab does not allow
++ * us to dump all the objects in one hit when we do a umount and tear
++ * down all the tnodes and objects. slab requires that we first free
++ * the individual objects.
++ *
++ * Once yaffs has been mainlined I shall try to motivate for a change
++ * to slab to provide the extra features we need here.
++ */
++
++struct yaffs_tnode_list {
++ struct yaffs_tnode_list *next;
++ struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++ struct yaffs_obj_list *next;
++ struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++ int n_tnodes_created;
++ struct yaffs_tnode *free_tnodes;
++ int n_free_tnodes;
++ struct yaffs_tnode_list *alloc_tnode_list;
++
++ int n_obj_created;
++ struct list_head free_objs;
++ int n_free_objects;
++
++ struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->alloc_tnode_list) {
++ tmp = allocator->alloc_tnode_list->next;
++
++ kfree(allocator->alloc_tnode_list->tnodes);
++ kfree(allocator->alloc_tnode_list);
++ allocator->alloc_tnode_list = tmp;
++ }
++
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->alloc_tnode_list = NULL;
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ int i;
++ struct yaffs_tnode *new_tnodes;
++ u8 *mem;
++ struct yaffs_tnode *curr;
++ struct yaffs_tnode *next;
++ struct yaffs_tnode_list *tnl;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_tnodes < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
++ mem = (u8 *) new_tnodes;
++
++ if (!new_tnodes) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: Could not allocate Tnodes");
++ return YAFFS_FAIL;
++ }
++
++ /* New hookup for wide tnodes */
++ for (i = 0; i < n_tnodes - 1; i++) {
++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++ curr->internal[0] = next;
++ }
++
++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++ curr->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++ allocator->n_free_tnodes += n_tnodes;
++ allocator->n_tnodes_created += n_tnodes;
++
++ /* Now add this bunch of tnodes to a list for freeing up.
++ * NB If we can't add this to the management list it isn't fatal
++ * but it just means we can't free this bunch of tnodes later.
++ */
++ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
++ if (!tnl) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Could not add tnodes to management list");
++ return YAFFS_FAIL;
++ } else {
++ tnl->tnodes = new_tnodes;
++ tnl->next = allocator->alloc_tnode_list;
++ allocator->alloc_tnode_list = tnl;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
++
++ return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode *tn = NULL;
++
++ if (!allocator) {
++ BUG();
++ return NULL;
++ }
++
++ /* If there are none left make more */
++ if (!allocator->free_tnodes)
++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++ if (allocator->free_tnodes) {
++ tn = allocator->free_tnodes;
++ allocator->free_tnodes = allocator->free_tnodes->internal[0];
++ allocator->n_free_tnodes--;
++ }
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ if (tn) {
++ tn->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = tn;
++ allocator->n_free_tnodes++;
++ }
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++/*--------------- yaffs_obj alloaction ------------------------
++ *
++ * Free yaffs_objs are stored in a list using obj->siblings.
++ * The blocks of allocated objects are stored in a linked list.
++ */
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ allocator->allocated_obj_list = NULL;
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ struct yaffs_obj_list *tmp;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ while (allocator->allocated_obj_list) {
++ tmp = allocator->allocated_obj_list->next;
++ kfree(allocator->allocated_obj_list->objects);
++ kfree(allocator->allocated_obj_list);
++ allocator->allocated_obj_list = tmp;
++ }
++
++ INIT_LIST_HEAD(&allocator->free_objs);
++ allocator->n_free_objects = 0;
++ allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ int i;
++ struct yaffs_obj *new_objs;
++ struct yaffs_obj_list *list;
++
++ if (!allocator) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_obj < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
++ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
++
++ if (!new_objs || !list) {
++ kfree(new_objs);
++ new_objs = NULL;
++ kfree(list);
++ list = NULL;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Could not allocate more objects");
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++ for (i = 0; i < n_obj; i++)
++ list_add(&new_objs[i].siblings, &allocator->free_objs);
++
++ allocator->n_free_objects += n_obj;
++ allocator->n_obj_created += n_obj;
++
++ /* Now add this bunch of Objects to a list for freeing up. */
++
++ list->objects = new_objs;
++ list->next = allocator->allocated_obj_list;
++ allocator->allocated_obj_list = list;
++
++ return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = NULL;
++ struct list_head *lh;
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return obj;
++ }
++
++ /* If there are none left make more */
++ if (list_empty(&allocator->free_objs))
++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++ if (!list_empty(&allocator->free_objs)) {
++ lh = allocator->free_objs.next;
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ list_del_init(lh);
++ allocator->n_free_objects--;
++ }
++
++ return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ BUG();
++ return;
++ }
++
++ /* Link into the free list. */
++ list_add(&obj->siblings, &allocator->free_objs);
++ allocator->n_free_objects++;
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++
++ if (!dev->allocator) {
++ BUG();
++ return;
++ }
++
++ yaffs_deinit_raw_tnodes(dev);
++ yaffs_deinit_raw_objs(dev);
++ kfree(dev->allocator);
++ dev->allocator = NULL;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator;
++
++ if (dev->allocator) {
++ BUG();
++ return;
++ }
++
++ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
++ if (allocator) {
++ dev->allocator = allocator;
++ yaffs_init_raw_tnodes(dev);
++ yaffs_init_raw_objs(dev);
++ }
++}
++
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.h linux-3.4.90/fs/yaffs2/yaffs_allocator.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_allocator.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.c linux-3.4.90/fs/yaffs2/yaffs_attribs.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_attribs.c 2014-05-17 16:37:59.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return from_kuid(&init_user_ns, iattr->ia_uid);
++}
++
++static inline gid_t ia_gid_read(const struct iattr *iattr)
++{
++ return from_kgid(&init_user_ns, iattr->ia_gid);
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = make_kuid(&init_user_ns, uid);
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = make_kgid(&init_user_ns, gid);
++}
++#else
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++ return iattr->ia_uid;
++}
++
++static inline gid_t ia_gid_read(const struct iattr *iattr)
++{
++ return iattr->ia_gid;
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++ iattr->ia_uid = uid;
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++ iattr->ia_gid = gid;
++}
++#endif
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++ obj->yst_uid = oh->yst_uid;
++ obj->yst_gid = oh->yst_gid;
++ obj->yst_atime = oh->yst_atime;
++ obj->yst_mtime = oh->yst_mtime;
++ obj->yst_ctime = oh->yst_ctime;
++ obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++ oh->yst_uid = obj->yst_uid;
++ oh->yst_gid = obj->yst_gid;
++ oh->yst_atime = obj->yst_atime;
++ oh->yst_mtime = obj->yst_mtime;
++ oh->yst_ctime = obj->yst_ctime;
++ oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++ obj->yst_mtime = Y_CURRENT_TIME;
++ if (do_a)
++ obj->yst_atime = obj->yst_mtime;
++ if (do_c)
++ obj->yst_ctime = obj->yst_mtime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++ yaffs_load_current_time(obj, 1, 1);
++ obj->yst_rdev = rdev;
++ obj->yst_uid = uid;
++ obj->yst_gid = gid;
++}
++
++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++ YCHAR *alias = NULL;
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return obj->variant.file_variant.file_size;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = obj->variant.symlink_variant.alias;
++ if (!alias)
++ return 0;
++ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++ default:
++ return 0;
++ }
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = attr->ia_valid;
++
++ if (valid & ATTR_MODE)
++ obj->yst_mode = attr->ia_mode;
++ if (valid & ATTR_UID)
++ obj->yst_uid = ia_uid_read(attr);
++ if (valid & ATTR_GID)
++ obj->yst_gid = ia_gid_read(attr);
++
++ if (valid & ATTR_ATIME)
++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++ if (valid & ATTR_CTIME)
++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++ if (valid & ATTR_MTIME)
++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++ if (valid & ATTR_SIZE)
++ yaffs_resize_file(obj, attr->ia_size);
++
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = 0;
++
++ attr->ia_mode = obj->yst_mode;
++ valid |= ATTR_MODE;
++ ia_uid_write(attr, obj->yst_uid);
++ valid |= ATTR_UID;
++ ia_gid_write(attr, obj->yst_gid);
++ valid |= ATTR_GID;
++
++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++ valid |= ATTR_ATIME;
++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++ valid |= ATTR_CTIME;
++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++ valid |= ATTR_MTIME;
++
++ attr->ia_size = yaffs_get_file_size(obj);
++ valid |= ATTR_SIZE;
++
++ attr->ia_valid = valid;
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.h linux-3.4.90/fs/yaffs2/yaffs_attribs.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_attribs.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.c linux-3.4.90/fs/yaffs2/yaffs_bitmap.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_bitmap.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "BlockBits block %d is not valid",
++ blk);
++ BUG();
++ }
++ return dev->chunk_bits +
++ (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++ chunk < 0 || chunk >= dev->param.chunks_per_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Chunk Id (%d:%d) invalid",
++ blk, chunk);
++ BUG();
++ }
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++) {
++ if (*blk_bits)
++ return 1;
++ blk_bits++;
++ }
++ return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++ int n = 0;
++
++ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
++ n += hweight8(*blk_bits);
++
++ return n;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.h linux-3.4.90/fs/yaffs2/yaffs_bitmap.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_bitmap.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.4.90/fs/yaffs2/yaffs_checkptrw.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_checkptrw.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,474 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++struct yaffs_checkpt_chunk_hdr {
++ int version;
++ int seq;
++ u32 sum;
++ u32 xor;
++} ;
++
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++static int apply_block_offset(struct yaffs_dev *dev, int block)
++{
++ return block - dev->block_offset;
++}
++
++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ hdr.version = YAFFS_CHECKPOINT_VERSION;
++ hdr.seq = dev->checkpt_page_seq;
++ hdr.sum = dev->checkpt_sum;
++ hdr.xor = dev->checkpt_xor;
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
++}
++
++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_chunk_hdr hdr;
++
++ memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
++
++ dev->checkpt_byte_offs = sizeof(hdr);
++
++ return hdr.version == YAFFS_CHECKPOINT_VERSION &&
++ hdr.seq == dev->checkpt_page_seq &&
++ hdr.sum == dev->checkpt_sum &&
++ hdr.xor == dev->checkpt_xor;
++}
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpt blocks_avail = %d", blocks_avail);
++
++ return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (!dev->drv.drv_erase_fn)
++ return 0;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checking blocks %d to %d",
++ dev->internal_start_block, dev->internal_end_block);
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ int offset_i = apply_block_offset(dev, i);
++ int result;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "erasing checkpt block %d", i);
++
++ dev->n_erasures++;
++
++ result = dev->drv.drv_erase_fn(dev, offset_i);
++ if(result) {
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ dev->n_free_chunks +=
++ dev->param.chunks_per_block;
++ } else {
++ dev->drv.drv_mark_bad_fn(dev, offset_i);
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ }
++ }
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++ int i;
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block: erased %d reserved %d avail %d next %d ",
++ dev->n_erased_blocks, dev->param.n_reserved_blocks,
++ blocks_avail, dev->checkpt_next_block);
++
++ if (dev->checkpt_next_block >= 0 &&
++ dev->checkpt_next_block <= dev->internal_end_block &&
++ blocks_avail > 0) {
++
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev, i);
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ dev->checkpt_next_block = i + 1;
++ dev->checkpt_cur_block = i;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "allocating checkpt block %d", i);
++ return;
++ }
++ }
++ }
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_ext_tags tags;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: start: blocks %d next %d",
++ dev->blocks_in_checkpt, dev->checkpt_next_block);
++
++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ int chunk = i * dev->param.chunks_per_block;
++ enum yaffs_block_state state;
++ u32 seq;
++
++ dev->tagger.read_chunk_tags_fn(dev,
++ apply_chunk_offset(dev, chunk),
++ NULL, &tags);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
++ i, (int) state,
++ tags.obj_id, tags.seq_number,
++ tags.ecc_result);
++
++ if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ continue;
++
++ dev->tagger.query_block_fn(dev,
++ apply_block_offset(dev, i),
++ &state, &seq);
++ if (state == YAFFS_BLOCK_STATE_DEAD)
++ continue;
++
++ /* Right kind of block */
++ dev->checkpt_next_block = tags.obj_id;
++ dev->checkpt_cur_block = i;
++ dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
++ dev->blocks_in_checkpt++;
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "found checkpt block %d", i);
++ return;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++ int i;
++
++ dev->checkpt_open_write = writing;
++
++ /* Got the functions we need? */
++ if (!dev->tagger.write_chunk_tags_fn ||
++ !dev->tagger.read_chunk_tags_fn ||
++ !dev->drv.drv_erase_fn ||
++ !dev->drv.drv_mark_bad_fn)
++ return 0;
++
++ if (writing && !yaffs2_checkpt_space_ok(dev))
++ return 0;
++
++ if (!dev->checkpt_buffer)
++ dev->checkpt_buffer =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ dev->checkpt_page_seq = 0;
++ dev->checkpt_byte_count = 0;
++ dev->checkpt_sum = 0;
++ dev->checkpt_xor = 0;
++ dev->checkpt_cur_block = -1;
++ dev->checkpt_cur_chunk = -1;
++ dev->checkpt_next_block = dev->internal_start_block;
++
++ if (writing) {
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++ yaffs2_checkpt_init_chunk_hdr(dev);
++ return yaffs_checkpt_erase(dev);
++ }
++
++ /* Opening for a read */
++ /* Set to a value that will kick off a read */
++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++ /* A checkpoint block list of 1 checkpoint block per 16 block is
++ * (hopefully) going to be way more than we need */
++ dev->blocks_in_checkpt = 0;
++ dev->checkpt_max_blocks =
++ (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
++ dev->checkpt_block_list =
++ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
++
++ if (!dev->checkpt_block_list)
++ return 0;
++
++ for (i = 0; i < dev->checkpt_max_blocks; i++)
++ dev->checkpt_block_list[i] = -1;
++
++ return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++ u32 composite_sum;
++
++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
++ *sum = composite_sum;
++ return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++ int chunk;
++ int offset_chunk;
++ struct yaffs_ext_tags tags;
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_erased_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0)
++ return 0;
++
++ tags.is_deleted = 0;
++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
++ tags.chunk_id = dev->checkpt_page_seq + 1;
++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++ tags.n_bytes = dev->data_bytes_per_chunk;
++ if (dev->checkpt_cur_chunk == 0) {
++ /* First chunk we write for the block? Set block state to
++ checkpoint */
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, dev->checkpt_cur_block);
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ dev->blocks_in_checkpt++;
++ }
++
++ chunk =
++ dev->checkpt_cur_block * dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
++ tags.obj_id, tags.chunk_id);
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++
++ dev->n_page_writes++;
++
++ dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
++ dev->checkpt_buffer, &tags);
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++ dev->checkpt_cur_chunk = 0;
++ dev->checkpt_cur_block = -1;
++ }
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++ yaffs2_checkpt_init_chunk_hdr(dev);
++
++
++ return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (!dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++ ok = yaffs2_checkpt_flush_buffer(dev);
++ }
++
++ return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ struct yaffs_ext_tags tags;
++ int chunk;
++ int offset_chunk;
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0) {
++ ok = 0;
++ break;
++ }
++
++ chunk = dev->checkpt_cur_block *
++ dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ offset_chunk = apply_chunk_offset(dev, chunk);
++ dev->n_page_reads++;
++
++ /* read in the next chunk */
++ dev->tagger.read_chunk_tags_fn(dev,
++ offset_chunk,
++ dev->checkpt_buffer,
++ &tags);
++
++ if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++ ok = 0;
++ break;
++ }
++ if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
++ ok = 0;
++ break;
++ }
++
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++
++ if (dev->checkpt_cur_chunk >=
++ dev->param.chunks_per_block)
++ dev->checkpt_cur_block = -1;
++
++ }
++
++ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++ }
++
++ return i;
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->checkpt_open_write) {
++ if (dev->checkpt_byte_offs !=
++ sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
++ yaffs2_checkpt_flush_buffer(dev);
++ } else if (dev->checkpt_block_list) {
++ for (i = 0;
++ i < dev->blocks_in_checkpt &&
++ dev->checkpt_block_list[i] >= 0; i++) {
++ int blk = dev->checkpt_block_list[i];
++ struct yaffs_block_info *bi = NULL;
++
++ if (dev->internal_start_block <= blk &&
++ blk <= dev->internal_end_block)
++ bi = yaffs_get_block_info(dev, blk);
++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ }
++ kfree(dev->checkpt_block_list);
++ dev->checkpt_block_list = NULL;
++ }
++
++ dev->n_free_chunks -=
++ dev->blocks_in_checkpt * dev->param.chunks_per_block;
++ dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
++ dev->checkpt_byte_count);
++
++ if (dev->checkpt_buffer) {
++ /* free the buffer */
++ kfree(dev->checkpt_buffer);
++ dev->checkpt_buffer = NULL;
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++ /* Erase the checkpoint data */
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "checkpoint invalidate of %d blocks",
++ dev->blocks_in_checkpt);
++
++ return yaffs_checkpt_erase(dev);
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.4.90/fs/yaffs2/yaffs_checkptrw.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_checkptrw.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.c linux-3.4.90/fs/yaffs2/yaffs_ecc.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_ecc.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,281 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
++ * such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
++ * and therefore this bytes influence on the line parity.
++ */
++
++static const unsigned char column_parity_table[] = {
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned char line_parity = 0;
++ unsigned char line_parity_prime = 0;
++ unsigned char t;
++ unsigned char b;
++
++ for (i = 0; i < 256; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) { /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++ }
++
++ ecc[2] = (~col_parity) | 0x03;
++
++ t = 0;
++ if (line_parity & 0x80)
++ t |= 0x80;
++ if (line_parity_prime & 0x80)
++ t |= 0x40;
++ if (line_parity & 0x40)
++ t |= 0x20;
++ if (line_parity_prime & 0x40)
++ t |= 0x10;
++ if (line_parity & 0x20)
++ t |= 0x08;
++ if (line_parity_prime & 0x20)
++ t |= 0x04;
++ if (line_parity & 0x10)
++ t |= 0x02;
++ if (line_parity_prime & 0x10)
++ t |= 0x01;
++ ecc[1] = ~t;
++
++ t = 0;
++ if (line_parity & 0x08)
++ t |= 0x80;
++ if (line_parity_prime & 0x08)
++ t |= 0x40;
++ if (line_parity & 0x04)
++ t |= 0x20;
++ if (line_parity_prime & 0x04)
++ t |= 0x10;
++ if (line_parity & 0x02)
++ t |= 0x08;
++ if (line_parity_prime & 0x02)
++ t |= 0x04;
++ if (line_parity & 0x01)
++ t |= 0x02;
++ if (line_parity_prime & 0x01)
++ t |= 0x01;
++ ecc[0] = ~t;
++
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc)
++{
++ unsigned char d0, d1, d2; /* deltas */
++
++ d0 = read_ecc[0] ^ test_ecc[0];
++ d1 = read_ecc[1] ^ test_ecc[1];
++ d2 = read_ecc[2] ^ test_ecc[2];
++
++ if ((d0 | d1 | d2) == 0)
++ return 0; /* no error */
++
++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++ /* Single bit (recoverable) error in data */
++
++ unsigned byte;
++ unsigned bit;
++
++ bit = byte = 0;
++
++ if (d1 & 0x80)
++ byte |= 0x80;
++ if (d1 & 0x20)
++ byte |= 0x40;
++ if (d1 & 0x08)
++ byte |= 0x20;
++ if (d1 & 0x02)
++ byte |= 0x10;
++ if (d0 & 0x80)
++ byte |= 0x08;
++ if (d0 & 0x20)
++ byte |= 0x04;
++ if (d0 & 0x08)
++ byte |= 0x02;
++ if (d0 & 0x02)
++ byte |= 0x01;
++
++ if (d2 & 0x80)
++ bit |= 0x04;
++ if (d2 & 0x20)
++ bit |= 0x02;
++ if (d2 & 0x08)
++ bit |= 0x01;
++
++ data[byte] ^= (1 << bit);
++
++ return 1; /* Corrected the error */
++ }
++
++ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
++ /* Reccoverable error in ecc */
++
++ read_ecc[0] = test_ecc[0];
++ read_ecc[1] = test_ecc[1];
++ read_ecc[2] = test_ecc[2];
++
++ return 1; /* Corrected the error */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc_other)
++{
++ unsigned int i;
++ unsigned char col_parity = 0;
++ unsigned line_parity = 0;
++ unsigned line_parity_prime = 0;
++ unsigned char b;
++
++ for (i = 0; i < n_bytes; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) {
++ /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++
++ }
++
++ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++ ecc_other->line_parity = line_parity;
++ ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc)
++{
++ unsigned char delta_col; /* column parity delta */
++ unsigned delta_line; /* line parity delta */
++ unsigned delta_line_prime; /* line parity delta */
++ unsigned bit;
++
++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++ delta_line_prime =
++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++ if ((delta_col | delta_line | delta_line_prime) == 0)
++ return 0; /* no error */
++
++ if (delta_line == ~delta_line_prime &&
++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++ /* Single bit (recoverable) error in data */
++
++ bit = 0;
++
++ if (delta_col & 0x20)
++ bit |= 0x04;
++ if (delta_col & 0x08)
++ bit |= 0x02;
++ if (delta_col & 0x02)
++ bit |= 0x01;
++
++ if (delta_line >= n_bytes)
++ return -1;
++
++ data[delta_line] ^= (1 << bit);
++
++ return 1; /* corrected */
++ }
++
++ if ((hweight32(delta_line) +
++ hweight32(delta_line_prime) +
++ hweight8(delta_col)) == 1) {
++ /* Reccoverable error in ecc */
++
++ *read_ecc = *test_ecc;
++ return 1; /* corrected */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.h linux-3.4.90/fs/yaffs2/yaffs_ecc.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_ecc.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data.
++ * Thus, two such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++ unsigned char col_parity;
++ unsigned line_parity;
++ unsigned line_parity_prime;
++};
++
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc);
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.4.90/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_getblockinfo.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++ *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs: get_block_info block %d is not valid",
++ blk);
++ BUG();
++ }
++ return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_guts.c linux-3.4.90/fs/yaffs2/yaffs_guts.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_guts.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,5146 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsmarshall.h"
++#include "yaffs_nand.h"
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Forward declarations */
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve);
++
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size);
++
++/* Function to calculate chunk and offset */
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out)
++{
++ int chunk;
++ u32 offset;
++
++ chunk = (u32) (addr >> dev->chunk_shift);
++
++ if (dev->chunk_div == 1) {
++ /* easy power of 2 case */
++ offset = (u32) (addr & dev->chunk_mask);
++ } else {
++ /* Non power-of-2 case */
++
++ loff_t chunk_base;
++
++ chunk /= dev->chunk_div;
++
++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++ offset = (u32) (addr - chunk_base);
++ }
++
++ *chunk_out = chunk;
++ *offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static inline u32 calc_shifts_ceiling(u32 x)
++{
++ int extra_bits;
++ int shifts;
++
++ shifts = extra_bits = 0;
++
++ while (x > 1) {
++ if (x & 1)
++ extra_bits++;
++ x >>= 1;
++ shifts++;
++ }
++
++ if (extra_bits)
++ shifts++;
++
++ return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static inline u32 calc_shifts(u32 x)
++{
++ u32 shifts;
++
++ shifts = 0;
++
++ if (!x)
++ return 0;
++
++ while (!(x & 1)) {
++ x >>= 1;
++ shifts++;
++ }
++
++ return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++ int i;
++ u8 *buf = (u8 *) 1;
++
++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++ dev->temp_buffer[i].in_use = 0;
++ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ dev->temp_buffer[i].buffer = buf;
++ }
++
++ return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
++{
++ int i;
++
++ dev->temp_in_use++;
++ if (dev->temp_in_use > dev->max_temp)
++ dev->max_temp = dev->temp_in_use;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].in_use == 0) {
++ dev->temp_buffer[i].in_use = 1;
++ return dev->temp_buffer[i].buffer;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
++ /*
++ * If we got here then we have to allocate an unmanaged one
++ * This is not good.
++ */
++
++ dev->unmanaged_buffer_allocs++;
++ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
++{
++ int i;
++
++ dev->temp_in_use--;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].buffer == buffer) {
++ dev->temp_buffer[i].in_use = 0;
++ return;
++ }
++ }
++
++ if (buffer) {
++ /* assume it is an unmanaged one. */
++ yaffs_trace(YAFFS_TRACE_BUFFERS,
++ "Releasing unmanaged temp buffer");
++ kfree(buffer);
++ dev->unmanaged_buffer_deallocs++;
++ }
++
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) data;
++ (void) tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++ const struct yaffs_ext_tags *tags)
++{
++ (void) dev;
++ (void) nand_chunk;
++ (void) tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++ if (!bi->gc_prioritise) {
++ bi->gc_prioritise = 1;
++ dev->has_pending_prioritised_gc = 1;
++ bi->chunk_error_strikes++;
++
++ if (bi->chunk_error_strikes > 3) {
++ bi->needs_retiring = 1; /* Too many stikes, so retire */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Block struck out");
++
++ }
++ }
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++ int erased_ok)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs_handle_chunk_error(dev, bi);
++
++ if (erased_ok) {
++ /* Was an actual write failure,
++ * so mark the block for retirement.*/
++ bi->needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d needs retiring", flash_block);
++ }
++
++ /* Delete the chunk */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ * Simple hash function. Needs to have a reasonable spread
++ */
++
++static inline int yaffs_hash_fn(int n)
++{
++ if (n < 0)
++ n = -n;
++ return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++ return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++ return dev->lost_n_found;
++}
++
++/*
++ * Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 *buffer, int n_bytes)
++{
++ /* Horrible, slow implementation */
++ while (n_bytes--) {
++ if (*buffer != 0xff)
++ return 0;
++ buffer++;
++ }
++ return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++ int retval = YAFFS_OK;
++ u8 *data = yaffs_get_temp_buffer(dev);
++ struct yaffs_ext_tags tags;
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++ retval = YAFFS_FAIL;
++
++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
++ tags.chunk_used) {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not erased", nand_chunk);
++ retval = YAFFS_FAIL;
++ }
++
++ yaffs_release_temp_buffer(dev, data);
++
++ return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = YAFFS_OK;
++ struct yaffs_ext_tags temp_tags;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++ temp_tags.obj_id != tags->obj_id ||
++ temp_tags.chunk_id != tags->chunk_id ||
++ temp_tags.n_bytes != tags->n_bytes)
++ retval = YAFFS_FAIL;
++
++ yaffs_release_temp_buffer(dev, buffer);
++
++ return retval;
++}
++
++
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
++{
++ int reserved_chunks;
++ int reserved_blocks = dev->param.n_reserved_blocks;
++ int checkpt_blocks;
++
++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
++
++ reserved_chunks =
++ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
++
++ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
++}
++
++static int yaffs_find_alloc_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_block_info *bi;
++
++ if (dev->n_erased_blocks < 1) {
++ /* Hoosterman we've got a problem.
++ * Can't get space to gc
++ */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no more erased blocks");
++
++ return -1;
++ }
++
++ /* Find an empty block. */
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ dev->alloc_block_finder++;
++ if (dev->alloc_block_finder < dev->internal_start_block
++ || dev->alloc_block_finder > dev->internal_end_block) {
++ dev->alloc_block_finder = dev->internal_start_block;
++ }
++
++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->seq_number++;
++ bi->seq_number = dev->seq_number;
++ dev->n_erased_blocks--;
++ yaffs_trace(YAFFS_TRACE_ALLOCATE,
++ "Allocated block %d, seq %d, %d left" ,
++ dev->alloc_block_finder, dev->seq_number,
++ dev->n_erased_blocks);
++ return dev->alloc_block_finder;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs tragedy: no more erased blocks, but there should have been %d",
++ dev->n_erased_blocks);
++
++ return -1;
++}
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++ struct yaffs_block_info **block_ptr)
++{
++ int ret_val;
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block < 0) {
++ /* Get next block to allocate off */
++ dev->alloc_block = yaffs_find_alloc_block(dev);
++ dev->alloc_page = 0;
++ }
++
++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
++ /* No space unless we're allowed to use the reserve. */
++ return -1;
++ }
++
++ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
++ && dev->alloc_page == 0)
++ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
++
++ /* Next page please.... */
++ if (dev->alloc_block >= 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++
++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
++ dev->alloc_page;
++ bi->pages_in_use++;
++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
++
++ dev->alloc_page++;
++
++ dev->n_free_chunks--;
++
++ /* If the block is full set the state to full */
++ if (dev->alloc_page >= dev->param.chunks_per_block) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ if (block_ptr)
++ *block_ptr = bi;
++
++ return ret_val;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
++
++ return -1;
++}
++
++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
++{
++ int n;
++
++ n = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ if (dev->alloc_block > 0)
++ n += (dev->param.chunks_per_block - dev->alloc_page);
++
++ return n;
++
++}
++
++/*
++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
++{
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block > 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++ }
++}
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++ const u8 *data,
++ struct yaffs_ext_tags *tags, int use_reserver)
++{
++ int attempts = 0;
++ int write_ok = 0;
++ int chunk;
++
++ yaffs2_checkpt_invalidate(dev);
++
++ do {
++ struct yaffs_block_info *bi = 0;
++ int erased_ok = 0;
++
++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
++ if (chunk < 0) {
++ /* no space */
++ break;
++ }
++
++ /* First check this chunk is erased, if it needs
++ * checking. The checking policy (unless forced
++ * always on) is as follows:
++ *
++ * Check the first page we try to write in a block.
++ * If the check passes then we don't need to check any
++ * more. If the check fails, we check again...
++ * If the block has been erased, we don't need to check.
++ *
++ * However, if the block has been prioritised for gc,
++ * then we think there might be something odd about
++ * this block and stop using it.
++ *
++ * Rationale: We should only ever see chunks that have
++ * not been erased if there was a partially written
++ * chunk due to power loss. This checking policy should
++ * catch that case with very few checks and thus save a
++ * lot of checks that are most likely not needed.
++ *
++ * Mods to the above
++ * If an erase check fails or the write fails we skip the
++ * rest of the block.
++ */
++
++ /* let's give it a try */
++ attempts++;
++
++ if (dev->param.always_check_erased)
++ bi->skip_erased_check = 0;
++
++ if (!bi->skip_erased_check) {
++ erased_ok = yaffs_check_chunk_erased(dev, chunk);
++ if (erased_ok != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs chunk %d was not erased",
++ chunk);
++
++ /* If not erased, delete this one,
++ * skip rest of block and
++ * try another chunk */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++ continue;
++ }
++ }
++
++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
++
++ if (!bi->skip_erased_check)
++ write_ok =
++ yaffs_verify_chunk_written(dev, chunk, data, tags);
++
++ if (write_ok != YAFFS_OK) {
++ /* Clean up aborted write, skip to next block and
++ * try another chunk */
++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
++ continue;
++ }
++
++ bi->skip_erased_check = 1;
++
++ /* Copy the data into the robustification buffer */
++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
++
++ } while (write_ok != YAFFS_OK &&
++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++ if (!write_ok)
++ chunk = -1;
++
++ if (attempts > 1) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>> yaffs write required %d attempts",
++ attempts);
++ dev->n_retried_writes += (attempts - 1);
++ }
++
++ return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to mark bad and erase block %d",
++ flash_block);
++ } else {
++ struct yaffs_ext_tags tags;
++ int chunk_id =
++ flash_block * dev->param.chunks_per_block;
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ memset(&tags, 0, sizeof(tags));
++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
++ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
++ dev->chunk_offset,
++ buffer,
++ &tags) != YAFFS_OK)
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Failed to write bad block marker to block %d",
++ flash_block);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++ }
++
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ bi->gc_prioritise = 0;
++ bi->needs_retiring = 0;
++
++ dev->n_retired_blocks++;
++}
++
++/*---------------- Name handling functions ------------*/
++
++static u16 yaffs_calc_name_sum(const YCHAR *name)
++{
++ u16 sum = 0;
++ u16 i = 1;
++
++ if (!name)
++ return 0;
++
++ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
++
++ /* 0x1f mask is case insensitive */
++ sum += ((*name) & 0x1f) * i;
++ i++;
++ name++;
++ }
++ return sum;
++}
++
++
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
++{
++ memset(obj->short_name, 0, sizeof(obj->short_name));
++
++ if (name && !name[0]) {
++ yaffs_fix_null_name(obj, obj->short_name,
++ YAFFS_SHORT_NAME_LENGTH);
++ name = obj->short_name;
++ } else if (name &&
++ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
++ YAFFS_SHORT_NAME_LENGTH) {
++ strcpy(obj->short_name, name);
++ }
++
++ obj->sum = yaffs_calc_name_sum(name);
++}
++
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
++ memset(tmp_name, 0, sizeof(tmp_name));
++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_set_obj_name(obj, tmp_name);
++#else
++ yaffs_set_obj_name(obj, oh->name);
++#endif
++}
++
++loff_t yaffs_max_file_size(struct yaffs_dev *dev)
++{
++ if(sizeof(loff_t) < 8)
++ return YAFFS_MAX_FILE_SIZE_32;
++ else
++ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
++
++ if (tn) {
++ memset(tn, 0, dev->tnode_size);
++ dev->n_tnodes++;
++ }
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ yaffs_free_raw_tnode(dev, tn);
++ dev->n_tnodes--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ yaffs_deinit_raw_tnodes_and_objs(dev);
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++}
++
++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos, unsigned val)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 mask;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++ val >>= dev->chunk_grp_bits;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ mask = dev->tnode_mask << bit_in_word;
++
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val << bit_in_word));
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ mask =
++ dev->tnode_mask >> bit_in_word;
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val >> bit_in_word));
++ }
++}
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 val;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ val = map[word_in_map] >> bit_in_word;
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;
++ val |= (map[word_in_map] << bit_in_word);
++ }
++
++ val &= dev->tnode_mask;
++ val <<= dev->chunk_grp_bits;
++
++ return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of top_level
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id)
++{
++ struct yaffs_tnode *tn = file_struct->top;
++ u32 i;
++ int required_depth;
++ int level = file_struct->top_level;
++
++ (void) dev;
++
++ /* Check sane level and chunk Id */
++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (i) {
++ i >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level)
++ return NULL; /* Not tall enough, so we can't find it */
++
++ /* Traverse down to level 0 */
++ while (level > 0 && tn) {
++ tn = tn->internal[(chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (level - 1) *
++ YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK];
++ level--;
++ }
++
++ return tn;
++}
++
++/* add_find_tnode_0 finds the level 0 tnode if it exists,
++ * otherwise first expands the tree.
++ * This happens in two steps:
++ * 1. If the tree isn't tall enough, then make it taller.
++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the
++ * specified tn will be plugged into the ttree.
++ */
++
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn)
++{
++ int required_depth;
++ int i;
++ int l;
++ struct yaffs_tnode *tn;
++ u32 x;
++
++ /* Check sane level and page Id */
++ if (file_struct->top_level < 0 ||
++ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level) {
++ /* Not tall enough, gotta make the tree taller */
++ for (i = file_struct->top_level; i < required_depth; i++) {
++
++ tn = yaffs_get_tnode(dev);
++
++ if (tn) {
++ tn->internal[0] = file_struct->top;
++ file_struct->top = tn;
++ file_struct->top_level++;
++ } else {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs: no more tnodes");
++ return NULL;
++ }
++ }
++ }
++
++ /* Traverse down to level 0, adding anything we need */
++
++ l = file_struct->top_level;
++ tn = file_struct->top;
++
++ if (l > 0) {
++ while (l > 0 && tn) {
++ x = (chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK;
++
++ if ((l > 1) && !tn->internal[x]) {
++ /* Add missing non-level-zero tnode */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ } else if (l == 1) {
++ /* Looking from level 1 at level 0 */
++ if (passed_tn) {
++ /* If we already have one, release it */
++ if (tn->internal[x])
++ yaffs_free_tnode(dev,
++ tn->internal[x]);
++ tn->internal[x] = passed_tn;
++
++ } else if (!tn->internal[x]) {
++ /* Don't have one, none passed in */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ }
++ }
++
++ tn = tn->internal[x];
++ l--;
++ }
++ } else {
++ /* top is level 0 */
++ if (passed_tn) {
++ memcpy(tn, passed_tn,
++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
++ yaffs_free_tnode(dev, passed_tn);
++ }
++ }
++
++ return tn;
++}
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++ int chunk_obj)
++{
++ return (tags->chunk_id == chunk_obj &&
++ tags->obj_id == obj_id &&
++ !tags->is_deleted) ? 1 : 0;
++
++}
++
++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
++ struct yaffs_ext_tags *tags, int obj_id,
++ int inode_chunk)
++{
++ int j;
++
++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
++ if (yaffs_check_chunk_bit
++ (dev, the_chunk / dev->param.chunks_per_block,
++ the_chunk % dev->param.chunks_per_block)) {
++
++ if (dev->chunk_grp_size == 1)
++ return the_chunk;
++ else {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ tags);
++ if (yaffs_tags_match(tags,
++ obj_id, inode_chunk)) {
++ /* found it; */
++ return the_chunk;
++ }
++ }
++ }
++ the_chunk++;
++ }
++ return -1;
++}
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /*Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ int ret_val = -1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++ return ret_val;
++}
++
++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /* Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ struct yaffs_dev *dev = in->my_dev;
++ int ret_val = -1;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (!tn)
++ return ret_val;
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++
++ /* Delete the entry in the filestructure (if found) */
++ if (ret_val != -1)
++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
++
++ return ret_val;
++}
++
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan)
++{
++ /* NB in_scan is zero unless scanning.
++ * For forward scanning, in_scan is > 0;
++ * for backward scanning in_scan is < 0
++ *
++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
++ */
++
++ struct yaffs_tnode *tn;
++ struct yaffs_dev *dev = in->my_dev;
++ int existing_cunk;
++ struct yaffs_ext_tags existing_tags;
++ struct yaffs_ext_tags new_tags;
++ unsigned existing_serial, new_serial;
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
++ /* Just ignore an attempt at putting a chunk into a non-file
++ * during scanning.
++ * If it is not during Scanning then something went wrong!
++ */
++ if (!in_scan) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy:attempt to put data chunk into a non-file"
++ );
++ BUG();
++ }
++
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++
++ tn = yaffs_add_find_tnode_0(dev,
++ &in->variant.file_variant,
++ inode_chunk, NULL);
++ if (!tn)
++ return YAFFS_FAIL;
++
++ if (!nand_chunk)
++ /* Dummy insert, bail now */
++ return YAFFS_OK;
++
++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ if (in_scan != 0) {
++ /* If we're scanning then we need to test for duplicates
++ * NB This does not need to be efficient since it should only
++ * happen when the power fails during a write, then only one
++ * chunk should ever be affected.
++ *
++ * Correction for YAFFS2: This could happen quite a lot and we
++ * need to think about efficiency! TODO
++ * Update: For backward scanning we don't need to re-read tags
++ * so this is quite cheap.
++ */
++
++ if (existing_cunk > 0) {
++ /* NB Right now existing chunk will not be real
++ * chunk_id if the chunk group size > 1
++ * thus we have to do a FindChunkInFile to get the
++ * real chunk id.
++ *
++ * We have a duplicate now we need to decide which
++ * one to use:
++ *
++ * Backwards scanning YAFFS2: The old one is what
++ * we use, dump the new one.
++ * YAFFS1: Get both sets of tags and compare serial
++ * numbers.
++ */
++
++ if (in_scan > 0) {
++ /* Only do this for forward scanning */
++ yaffs_rd_chunk_tags_nand(dev,
++ nand_chunk,
++ NULL, &new_tags);
++
++ /* Do a proper find */
++ existing_cunk =
++ yaffs_find_chunk_in_file(in, inode_chunk,
++ &existing_tags);
++ }
++
++ if (existing_cunk <= 0) {
++ /*Hoosterman - how did this happen? */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: existing chunk < 0 in scan"
++ );
++
++ }
++
++ /* NB The deleted flags should be false, otherwise
++ * the chunks will not be loaded during a scan
++ */
++
++ if (in_scan > 0) {
++ new_serial = new_tags.serial_number;
++ existing_serial = existing_tags.serial_number;
++ }
++
++ if ((in_scan > 0) &&
++ (existing_cunk <= 0 ||
++ ((existing_serial + 1) & 3) == new_serial)) {
++ /* Forward scanning.
++ * Use new
++ * Delete the old one and drop through to
++ * update the tnode
++ */
++ yaffs_chunk_del(dev, existing_cunk, 1,
++ __LINE__);
++ } else {
++ /* Backward scanning or we want to use the
++ * existing one
++ * Delete the new one and return early so that
++ * the tnode isn't changed
++ */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++ }
++
++ }
++
++ if (existing_cunk == 0)
++ in->n_data_chunks++;
++
++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
++
++ return YAFFS_OK;
++}
++
++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
++{
++ struct yaffs_block_info *the_block;
++ unsigned block_no;
++
++ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
++
++ block_no = chunk / dev->param.chunks_per_block;
++ the_block = yaffs_get_block_info(dev, block_no);
++ if (the_block) {
++ the_block->soft_del_pages++;
++ dev->n_free_chunks++;
++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
++ }
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
++ * the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls
++ * the chunk out of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks
++ * are soft deleted.
++ */
++
++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
++ u32 level, int chunk_offset)
++{
++ int i;
++ int the_chunk;
++ int all_done = 1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = YAFFS_NTNODES_INTERNAL - 1;
++ all_done && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ all_done =
++ yaffs_soft_del_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ if (all_done) {
++ yaffs_free_tnode(dev,
++ tn->internal[i]);
++ tn->internal[i] = NULL;
++ } else {
++ /* Can this happen? */
++ }
++ }
++ }
++ return (all_done) ? 1 : 0;
++ }
++
++ /* level 0 */
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk) {
++ yaffs_soft_del_chunk(dev, the_chunk);
++ yaffs_load_tnode_0(dev, tn, i, 0);
++ }
++ }
++ return 1;
++}
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_obj *parent;
++
++ yaffs_verify_obj_in_dir(obj);
++ parent = obj->parent;
++
++ yaffs_verify_dir(parent);
++
++ if (dev && dev->param.remove_obj_fn)
++ dev->param.remove_obj_fn(obj);
++
++ list_del_init(&obj->siblings);
++ obj->parent = NULL;
++
++ yaffs_verify_dir(parent);
++}
++
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
++{
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a null pointer directory"
++ );
++ BUG();
++ return;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: Trying to add an object to a non-directory"
++ );
++ BUG();
++ }
++
++ if (obj->siblings.prev == NULL) {
++ /* Not initialised */
++ BUG();
++ }
++
++ yaffs_verify_dir(directory);
++
++ yaffs_remove_obj_from_dir(obj);
++
++ /* Now add it */
++ list_add(&obj->siblings, &directory->variant.dir_variant.children);
++ obj->parent = directory;
++
++ if (directory == obj->my_dev->unlinked_dir
++ || directory == obj->my_dev->del_dir) {
++ obj->unlinked = 1;
++ obj->my_dev->n_unlinked_files++;
++ obj->rename_allowed = 0;
++ }
++
++ yaffs_verify_dir(directory);
++ yaffs_verify_obj_in_dir(obj);
++}
++
++static int yaffs_change_obj_name(struct yaffs_obj *obj,
++ struct yaffs_obj *new_dir,
++ const YCHAR *new_name, int force, int shadows)
++{
++ int unlink_op;
++ int del_op;
++ struct yaffs_obj *existing_target;
++
++ if (new_dir == NULL)
++ new_dir = obj->parent; /* use the old directory */
++
++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_change_obj_name: new_dir is not a directory"
++ );
++ BUG();
++ }
++
++ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
++ del_op = (new_dir == obj->my_dev->del_dir);
++
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++
++ /* If the object is a file going into the unlinked directory,
++ * then it is OK to just stuff it in since duplicate names are OK.
++ * else only proceed if the new name does not exist and we're putting
++ * it into a directory.
++ */
++ if (!(unlink_op || del_op || force ||
++ shadows > 0 || !existing_target) ||
++ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ return YAFFS_FAIL;
++
++ yaffs_set_obj_name(obj, new_name);
++ obj->dirty = 1;
++ yaffs_add_obj_to_dir(new_dir, obj);
++
++ if (unlink_op)
++ obj->unlinked = 1;
++
++ /* If it is a deletion then we mark it as a shrink for gc */
++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++/*------------------------ Short Operations Cache ------------------------------
++ * In many situations where there is no high level buffering a lot of
++ * reads might be short sequential reads, and a lot of writes may be short
++ * sequential writes. eg. scanning/writing a jpeg file.
++ * In these cases, a short read/write cache can provide a huge perfomance
++ * benefit with dumb-as-a-rock code.
++ * In Linux, the page cache provides read buffering and the short op cache
++ * provides write buffering.
++ *
++ * There are a small number (~10) of cache chunks per device so that we don't
++ * need a very intelligent search.
++ */
++
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++ struct yaffs_cache *cache;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ for (i = 0; i < n_caches; i++) {
++ cache = &dev->cache[i];
++ if (cache->object == obj && cache->dirty)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void yaffs_flush_file_cache(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int lowest = -99; /* Stop compiler whining. */
++ int i;
++ struct yaffs_cache *cache;
++ int chunk_written = 0;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ if (n_caches < 1)
++ return;
++ do {
++ cache = NULL;
++
++ /* Find the lowest dirty chunk for this object */
++ for (i = 0; i < n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].dirty) {
++ if (!cache ||
++ dev->cache[i].chunk_id < lowest) {
++ cache = &dev->cache[i];
++ lowest = cache->chunk_id;
++ }
++ }
++ }
++
++ if (cache && !cache->locked) {
++ /* Write it out and free it up */
++ chunk_written =
++ yaffs_wr_data_obj(cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ cache->object = NULL;
++ }
++ } while (cache && chunk_written > 0);
++
++ if (cache)
++ /* Hoosterman, disk full while writing cache out. */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: no space during cache write");
++}
++
++/*yaffs_flush_whole_cache(dev)
++ *
++ *
++ */
++
++void yaffs_flush_whole_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int n_caches = dev->param.n_caches;
++ int i;
++
++ /* Find a dirty object in the cache and flush it...
++ * until there are no further dirty objects.
++ */
++ do {
++ obj = NULL;
++ for (i = 0; i < n_caches && !obj; i++) {
++ if (dev->cache[i].object && dev->cache[i].dirty)
++ obj = dev->cache[i].object;
++ }
++ if (obj)
++ yaffs_flush_file_cache(obj);
++ } while (obj);
++
++}
++
++/* Grab us a cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->param.n_caches > 0) {
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (!dev->cache[i].object)
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_cache *cache;
++ struct yaffs_obj *the_obj;
++ int usage;
++ int i;
++ int pushout;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ /* Try find a non-dirty one... */
++
++ cache = yaffs_grab_chunk_worker(dev);
++
++ if (!cache) {
++ /* They were all dirty, find the LRU object and flush
++ * its cache, then find again.
++ * NB what's here is not very accurate,
++ * we actually flush the object with the LRU chunk.
++ */
++
++ /* With locking we can't assume we can use entry zero,
++ * Set the_obj to a valid pointer for Coverity. */
++ the_obj = dev->cache[0].object;
++ usage = -1;
++ cache = NULL;
++ pushout = -1;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object &&
++ !dev->cache[i].locked &&
++ (dev->cache[i].last_use < usage ||
++ !cache)) {
++ usage = dev->cache[i].last_use;
++ the_obj = dev->cache[i].object;
++ cache = &dev->cache[i];
++ pushout = i;
++ }
++ }
++
++ if (!cache || cache->dirty) {
++ /* Flush and try again */
++ yaffs_flush_file_cache(the_obj);
++ cache = yaffs_grab_chunk_worker(dev);
++ }
++ }
++ return cache;
++}
++
++/* Find a cached chunk */
++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
++ int chunk_id)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return NULL;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].chunk_id == chunk_id) {
++ dev->cache_hits++;
++
++ return &dev->cache[i];
++ }
++ }
++ return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
++ int is_write)
++{
++ int i;
++
++ if (dev->param.n_caches < 1)
++ return;
++
++ if (dev->cache_last_use < 0 ||
++ dev->cache_last_use > 100000000) {
++ /* Reset the cache usages */
++ for (i = 1; i < dev->param.n_caches; i++)
++ dev->cache[i].last_use = 0;
++
++ dev->cache_last_use = 0;
++ }
++ dev->cache_last_use++;
++ cache->last_use = dev->cache_last_use;
++
++ if (is_write)
++ cache->dirty = 1;
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
++{
++ struct yaffs_cache *cache;
++
++ if (object->my_dev->param.n_caches > 0) {
++ cache = yaffs_find_chunk_cache(object, chunk_id);
++
++ if (cache)
++ cache->object = NULL;
++ }
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.n_caches > 0) {
++ /* Invalidate it. */
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == in)
++ dev->cache[i].object = NULL;
++ }
++ }
++}
++
++static void yaffs_unhash_obj(struct yaffs_obj *obj)
++{
++ int bucket;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ /* If it is still linked into the bucket list, free from the list */
++ if (!list_empty(&obj->hash_link)) {
++ list_del_init(&obj->hash_link);
++ bucket = yaffs_hash_fn(obj->obj_id);
++ dev->obj_bucket[bucket].count--;
++ }
++}
++
++/* FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_free_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj) {
++ BUG();
++ return;
++ }
++ dev = obj->my_dev;
++ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
++ obj, obj->my_inode);
++ if (obj->parent)
++ BUG();
++ if (!list_empty(&obj->siblings))
++ BUG();
++
++ if (obj->my_inode) {
++ /* We're still hooked up to a cached inode.
++ * Don't delete now, but mark for later deletion
++ */
++ obj->defered_free = 1;
++ return;
++ }
++
++ yaffs_unhash_obj(obj);
++
++ yaffs_free_raw_obj(dev, obj);
++ dev->n_obj--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj)
++{
++ if (obj->defered_free)
++ yaffs_free_obj(obj);
++}
++
++static int yaffs_generic_obj_del(struct yaffs_obj *in)
++{
++ /* Iinvalidate the file's data in the cache, without flushing. */
++ yaffs_invalidate_whole_cache(in);
++
++ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
++ /* Move to unlinked directory so we have a deletion record */
++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
++ 0);
++ }
++
++ yaffs_remove_obj_from_dir(in);
++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
++ in->hdr_chunk = 0;
++
++ yaffs_free_obj(in);
++ return YAFFS_OK;
++
++}
++
++static void yaffs_soft_del_file(struct yaffs_obj *obj)
++{
++ if (!obj->deleted ||
++ obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
++ obj->soft_del)
++ return;
++
++ if (obj->n_data_chunks <= 0) {
++ /* Empty file with no duplicate object headers,
++ * just delete it immediately */
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: Deleting empty file %d",
++ obj->obj_id);
++ yaffs_generic_obj_del(obj);
++ } else {
++ yaffs_soft_del_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.
++ file_variant.top_level, 0);
++ obj->soft_del = 1;
++ }
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
++ struct yaffs_tnode *tn, u32 level,
++ int del0)
++{
++ int i;
++ int has_data;
++
++ if (!tn)
++ return tn;
++
++ has_data = 0;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i]) {
++ tn->internal[i] =
++ yaffs_prune_worker(dev,
++ tn->internal[i],
++ level - 1,
++ (i == 0) ? del0 : 1);
++ }
++
++ if (tn->internal[i])
++ has_data++;
++ }
++ } else {
++ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
++ u32 *map = (u32 *) tn;
++
++ for (i = 0; !has_data && i < tnode_size_u32; i++) {
++ if (map[i])
++ has_data++;
++ }
++ }
++
++ if (has_data == 0 && del0) {
++ /* Free and return NULL */
++ yaffs_free_tnode(dev, tn);
++ tn = NULL;
++ }
++ return tn;
++}
++
++static int yaffs_prune_tree(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct)
++{
++ int i;
++ int has_data;
++ int done = 0;
++ struct yaffs_tnode *tn;
++
++ if (file_struct->top_level < 1)
++ return YAFFS_OK;
++
++ file_struct->top =
++ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
++
++ /* Now we have a tree with all the non-zero branches NULL but
++ * the height is the same as it was.
++ * Let's see if we can trim internal tnodes to shorten the tree.
++ * We can do this if only the 0th element in the tnode is in use
++ * (ie all the non-zero are NULL)
++ */
++
++ while (file_struct->top_level && !done) {
++ tn = file_struct->top;
++
++ has_data = 0;
++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i])
++ has_data++;
++ }
++
++ if (!has_data) {
++ file_struct->top = tn->internal[0];
++ file_struct->top_level--;
++ yaffs_free_tnode(dev, tn);
++ } else {
++ done = 1;
++ }
++ }
++
++ return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* alloc_empty_obj gets us a clean Object.*/
++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
++
++ if (!obj)
++ return obj;
++
++ dev->n_obj++;
++
++ /* Now sweeten it up... */
++
++ memset(obj, 0, sizeof(struct yaffs_obj));
++ obj->being_created = 1;
++
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0;
++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
++ INIT_LIST_HEAD(&(obj->hard_links));
++ INIT_LIST_HEAD(&(obj->hash_link));
++ INIT_LIST_HEAD(&obj->siblings);
++
++ /* Now make the directory sane */
++ if (dev->root_dir) {
++ obj->parent = dev->root_dir;
++ list_add(&(obj->siblings),
++ &dev->root_dir->variant.dir_variant.children);
++ }
++
++ /* Add it to the lost and found directory.
++ * NB Can't put root or lost-n-found in lost-n-found so
++ * check if lost-n-found exists first
++ */
++ if (dev->lost_n_found)
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++
++ obj->being_created = 0;
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return obj;
++}
++
++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
++{
++ int i;
++ int l = 999;
++ int lowest = 999999;
++
++ /* Search for the shortest list or one that
++ * isn't too long.
++ */
++
++ for (i = 0; i < 10 && lowest > 4; i++) {
++ dev->bucket_finder++;
++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
++ lowest = dev->obj_bucket[dev->bucket_finder].count;
++ l = dev->bucket_finder;
++ }
++ }
++
++ return l;
++}
++
++static int yaffs_new_obj_id(struct yaffs_dev *dev)
++{
++ int bucket = yaffs_find_nice_bucket(dev);
++ int found = 0;
++ struct list_head *i;
++ u32 n = (u32) bucket;
++
++ /* Now find an object value that has not already been taken
++ * by scanning the list.
++ */
++
++ while (!found) {
++ found = 1;
++ n += YAFFS_NOBJECT_BUCKETS;
++ if (1 || dev->obj_bucket[bucket].count > 0) {
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* If there is already one in the list */
++ if (i && list_entry(i, struct yaffs_obj,
++ hash_link)->obj_id == n) {
++ found = 0;
++ }
++ }
++ }
++ }
++ return n;
++}
++
++static void yaffs_hash_obj(struct yaffs_obj *in)
++{
++ int bucket = yaffs_hash_fn(in->obj_id);
++ struct yaffs_dev *dev = in->my_dev;
++
++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
++ dev->obj_bucket[bucket].count++;
++}
++
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
++{
++ int bucket = yaffs_hash_fn(number);
++ struct list_head *i;
++ struct yaffs_obj *in;
++
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* Look if it is in the list */
++ in = list_entry(i, struct yaffs_obj, hash_link);
++ if (in->obj_id == number) {
++ /* Don't show if it is defered free */
++ if (in->defered_free)
++ return NULL;
++ return in;
++ }
++ }
++
++ return NULL;
++}
++
++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++ struct yaffs_tnode *tn = NULL;
++
++ if (number < 0)
++ number = yaffs_new_obj_id(dev);
++
++ if (type == YAFFS_OBJECT_TYPE_FILE) {
++ tn = yaffs_get_tnode(dev);
++ if (!tn)
++ return NULL;
++ }
++
++ the_obj = yaffs_alloc_empty_obj(dev);
++ if (!the_obj) {
++ if (tn)
++ yaffs_free_tnode(dev, tn);
++ return NULL;
++ }
++
++ the_obj->fake = 0;
++ the_obj->rename_allowed = 1;
++ the_obj->unlink_allowed = 1;
++ the_obj->obj_id = number;
++ yaffs_hash_obj(the_obj);
++ the_obj->variant_type = type;
++ yaffs_load_current_time(the_obj, 1, 1);
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ the_obj->variant.file_variant.file_size = 0;
++ the_obj->variant.file_variant.scanned_size = 0;
++ the_obj->variant.file_variant.shrink_size =
++ yaffs_max_file_size(dev);
++ the_obj->variant.file_variant.top_level = 0;
++ the_obj->variant.file_variant.top = tn;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* No action required */
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* todo this should not happen */
++ break;
++ }
++ return the_obj;
++}
++
++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
++ int number, u32 mode)
++{
++
++ struct yaffs_obj *obj =
++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++
++ if (!obj)
++ return NULL;
++
++ obj->fake = 1; /* it is fake so it might not use NAND */
++ obj->rename_allowed = 0;
++ obj->unlink_allowed = 0;
++ obj->deleted = 0;
++ obj->unlinked = 0;
++ obj->yst_mode = mode;
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0; /* Not a valid chunk. */
++ return obj;
++
++}
++
++
++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ int i;
++
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++ yaffs_init_raw_tnodes_and_objs(dev);
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
++ dev->obj_bucket[i].count = 0;
++ }
++}
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++
++ if (number > 0)
++ the_obj = yaffs_find_by_number(dev, number);
++
++ if (!the_obj)
++ the_obj = yaffs_new_obj(dev, number, type);
++
++ return the_obj;
++
++}
++
++YCHAR *yaffs_clone_str(const YCHAR *str)
++{
++ YCHAR *new_str = NULL;
++ int len;
++
++ if (!str)
++ str = _Y("");
++
++ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
++ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
++ if (new_str) {
++ strncpy(new_str, str, len);
++ new_str[len] = 0;
++ }
++ return new_str;
++
++}
++/*
++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ * create dir/a : update dir's mtime/ctime
++ * rm dir/a: update dir's mtime/ctime
++ * modify dir/a: don't update dir's mtimme/ctime
++ *
++ * This can be handled immediately or defered. Defering helps reduce the number
++ * of updates when many files in a directory are changed within a brief period.
++ *
++ * If the directory updating is defered then yaffs_update_dirty_dirs must be
++ * called periodically.
++ */
++
++static void yaffs_update_parent(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ if (!obj)
++ return;
++ dev = obj->my_dev;
++ obj->dirty = 1;
++ yaffs_load_current_time(obj, 0, 1);
++ if (dev->param.defered_dir_update) {
++ struct list_head *link = &obj->variant.dir_variant.dirty;
++
++ if (list_empty(link)) {
++ list_add(link, &dev->dirty_dirs);
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Added object %d to dirty directories",
++ obj->obj_id);
++ }
++
++ } else {
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
++{
++ struct list_head *link;
++ struct yaffs_obj *obj;
++ struct yaffs_dir_var *d_s;
++ union yaffs_obj_var *o_v;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
++
++ while (!list_empty(&dev->dirty_dirs)) {
++ link = dev->dirty_dirs.next;
++ list_del_init(link);
++
++ d_s = list_entry(link, struct yaffs_dir_var, dirty);
++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
++ obj = list_entry(o_v, struct yaffs_obj, variant);
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
++ obj->obj_id);
++
++ if (obj->dirty)
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++/*
++ * Mknod (create) a new object.
++ * equiv_obj only has meaning for a hard link;
++ * alias_str only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
++ struct yaffs_obj *parent,
++ const YCHAR *name,
++ u32 mode,
++ u32 uid,
++ u32 gid,
++ struct yaffs_obj *equiv_obj,
++ const YCHAR *alias_str, u32 rdev)
++{
++ struct yaffs_obj *in;
++ YCHAR *str = NULL;
++ struct yaffs_dev *dev = parent->my_dev;
++
++ /* Check if the entry exists.
++ * If it does then fail the call since we don't want a dup. */
++ if (yaffs_find_by_name(parent, name))
++ return NULL;
++
++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ str = yaffs_clone_str(alias_str);
++ if (!str)
++ return NULL;
++ }
++
++ in = yaffs_new_obj(dev, -1, type);
++
++ if (!in) {
++ kfree(str);
++ return NULL;
++ }
++
++ in->hdr_chunk = 0;
++ in->valid = 1;
++ in->variant_type = type;
++
++ in->yst_mode = mode;
++
++ yaffs_attribs_init(in, gid, uid, rdev);
++
++ in->n_data_chunks = 0;
++
++ yaffs_set_obj_name(in, name);
++ in->dirty = 1;
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ in->my_dev = parent->my_dev;
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.alias = str;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardlink_variant.equiv_obj = equiv_obj;
++ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
++ list_add(&in->hard_links, &equiv_obj->hard_links);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* do nothing */
++ break;
++ }
++
++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
++ /* Could not create the object header, fail */
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ if (in)
++ yaffs_update_parent(parent);
++
++ return in;
++}
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++ uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++ mode, uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++ uid, gid, NULL, NULL, rdev);
++}
++
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++ uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_link_obj returns the object id of the equivalent object.*/
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++ struct yaffs_obj *equiv_obj)
++{
++ /* Get the real object in case we were fed a hard link obj */
++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
++
++ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
++ parent, name, 0, 0, 0,
++ equiv_obj, NULL, 0))
++ return equiv_obj;
++
++ return NULL;
++
++}
++
++
++
++/*---------------------- Block Management and Page Allocation -------------*/
++
++static void yaffs_deinit_blocks(struct yaffs_dev *dev)
++{
++ if (dev->block_info_alt && dev->block_info)
++ vfree(dev->block_info);
++ else
++ kfree(dev->block_info);
++
++ dev->block_info_alt = 0;
++
++ dev->block_info = NULL;
++
++ if (dev->chunk_bits_alt && dev->chunk_bits)
++ vfree(dev->chunk_bits);
++ else
++ kfree(dev->chunk_bits);
++ dev->chunk_bits_alt = 0;
++ dev->chunk_bits = NULL;
++}
++
++static int yaffs_init_blocks(struct yaffs_dev *dev)
++{
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ dev->block_info = NULL;
++ dev->chunk_bits = NULL;
++ dev->alloc_block = -1; /* force it to get a new one */
++
++ /* If the first allocation strategy fails, thry the alternate one */
++ dev->block_info =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
++ if (!dev->block_info) {
++ dev->block_info =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_info));
++ dev->block_info_alt = 1;
++ } else {
++ dev->block_info_alt = 0;
++ }
++
++ if (!dev->block_info)
++ goto alloc_error;
++
++ /* Set up dynamic blockinfo stuff. Round up bytes. */
++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
++ dev->chunk_bits =
++ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
++ if (!dev->chunk_bits) {
++ dev->chunk_bits =
++ vmalloc(dev->chunk_bit_stride * n_blocks);
++ dev->chunk_bits_alt = 1;
++ } else {
++ dev->chunk_bits_alt = 0;
++ }
++ if (!dev->chunk_bits)
++ goto alloc_error;
++
++
++ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
++ return YAFFS_OK;
++
++alloc_error:
++ yaffs_deinit_blocks(dev);
++ return YAFFS_FAIL;
++}
++
++
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
++ int erased_ok = 0;
++ int i;
++
++ /* If the block is still healthy erase it and mark as clean.
++ * If the block has had a data failure, then retire it.
++ */
++
++ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++ "yaffs_block_became_dirty block %d state %d %s",
++ block_no, bi->block_state,
++ (bi->needs_retiring) ? "needs retiring" : "");
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
++
++ /* If this is the block being garbage collected then stop gc'ing */
++ if (block_no == dev->gc_block)
++ dev->gc_block = 0;
++
++ /* If this block is currently the best candidate for gc
++ * then drop as a candidate */
++ if (block_no == dev->gc_dirtiest) {
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ }
++
++ if (!bi->needs_retiring) {
++ yaffs2_checkpt_invalidate(dev);
++ erased_ok = yaffs_erase_block(dev, block_no);
++ if (!erased_ok) {
++ dev->n_erase_failures++;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Erasure failed %d", block_no);
++ }
++ }
++
++ /* Verify erasure if needed */
++ if (erased_ok &&
++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
++ !yaffs_skip_verification(dev))) {
++ for (i = 0; i < dev->param.chunks_per_block; i++) {
++ if (!yaffs_check_chunk_erased(dev,
++ block_no * dev->param.chunks_per_block + i)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ ">>Block %d erasure supposedly OK, but chunk %d not erased",
++ block_no, i);
++ }
++ }
++ }
++
++ if (!erased_ok) {
++ /* We lost a block of free space */
++ dev->n_free_chunks -= dev->param.chunks_per_block;
++ yaffs_retire_block(dev, block_no);
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>> Block %d retired", block_no);
++ return;
++ }
++
++ /* Clean it up... */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ bi->seq_number = 0;
++ dev->n_erased_blocks++;
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++ bi->has_shrink_hdr = 0;
++ bi->skip_erased_check = 1; /* Clean, so no need to check */
++ bi->gc_prioritise = 0;
++ bi->has_summary = 0;
++
++ yaffs_clear_chunk_bits(dev, block_no);
++
++ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
++}
++
++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int old_chunk, u8 *buffer)
++{
++ int new_chunk;
++ int mark_flash = 1;
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj *object;
++ int matching_chunk;
++ int ret_val = YAFFS_OK;
++
++ memset(&tags, 0, sizeof(tags));
++ yaffs_rd_chunk_tags_nand(dev, old_chunk,
++ buffer, &tags);
++ object = yaffs_find_by_number(dev, tags.obj_id);
++
++ yaffs_trace(YAFFS_TRACE_GC_DETAIL,
++ "Collecting chunk in block %d, %d %d %d ",
++ dev->gc_chunk, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++
++ if (object && !yaffs_skip_verification(dev)) {
++ if (tags.chunk_id == 0)
++ matching_chunk =
++ object->hdr_chunk;
++ else if (object->soft_del)
++ /* Defeat the test */
++ matching_chunk = old_chunk;
++ else
++ matching_chunk =
++ yaffs_find_chunk_in_file
++ (object, tags.chunk_id,
++ NULL);
++
++ if (old_chunk != matching_chunk)
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "gc: page in gc mismatch: %d %d %d %d",
++ old_chunk,
++ matching_chunk,
++ tags.obj_id,
++ tags.chunk_id);
++ }
++
++ if (!object) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "page %d in gc has no object: %d %d %d ",
++ old_chunk,
++ tags.obj_id, tags.chunk_id,
++ tags.n_bytes);
++ }
++
++ if (object &&
++ object->deleted &&
++ object->soft_del && tags.chunk_id != 0) {
++ /* Data chunk in a soft deleted file,
++ * throw it away.
++ * It's a soft deleted data chunk,
++ * No need to copy this, just forget
++ * about it and fix up the object.
++ */
++
++ /* Free chunks already includes
++ * softdeleted chunks, how ever this
++ * chunk is going to soon be really
++ * deleted which will increment free
++ * chunks. We have to decrement free
++ * chunks so this works out properly.
++ */
++ dev->n_free_chunks--;
++ bi->soft_del_pages--;
++
++ object->n_data_chunks--;
++ if (object->n_data_chunks <= 0) {
++ /* remeber to clean up obj */
++ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
++ dev->n_clean_ups++;
++ }
++ mark_flash = 0;
++ } else if (object) {
++ /* It's either a data chunk in a live
++ * file or an ObjectHeader, so we're
++ * interested in it.
++ * NB Need to keep the ObjectHeaders of
++ * deleted files until the whole file
++ * has been deleted off
++ */
++ tags.serial_number++;
++ dev->n_gc_copies++;
++
++ if (tags.chunk_id == 0) {
++ /* It is an object Id,
++ * We need to nuke the
++ * shrinkheader flags since its
++ * work is done.
++ * Also need to clean up
++ * shadowing.
++ */
++ struct yaffs_obj_hdr *oh;
++ oh = (struct yaffs_obj_hdr *) buffer;
++
++ oh->is_shrink = 0;
++ tags.extra_is_shrink = 0;
++ oh->shadows_obj = 0;
++ oh->inband_shadowed_obj_id = 0;
++ tags.extra_shadows = 0;
++
++ /* Update file size */
++ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++ yaffs_oh_size_load(oh,
++ object->variant.file_variant.file_size);
++ tags.extra_file_size =
++ object->variant.file_variant.file_size;
++ }
++
++ yaffs_verify_oh(object, oh, &tags, 1);
++ new_chunk =
++ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
++ } else {
++ new_chunk =
++ yaffs_write_new_chunk(dev, buffer, &tags, 1);
++ }
++
++ if (new_chunk < 0) {
++ ret_val = YAFFS_FAIL;
++ } else {
++
++ /* Now fix up the Tnodes etc. */
++
++ if (tags.chunk_id == 0) {
++ /* It's a header */
++ object->hdr_chunk = new_chunk;
++ object->serial = tags.serial_number;
++ } else {
++ /* It's a data chunk */
++ yaffs_put_chunk_in_file(object, tags.chunk_id,
++ new_chunk, 0);
++ }
++ }
++ }
++ if (ret_val == YAFFS_OK)
++ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
++ return ret_val;
++}
++
++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
++{
++ int old_chunk;
++ int ret_val = YAFFS_OK;
++ int i;
++ int is_checkpt_block;
++ int max_copies;
++ int chunks_before = yaffs_get_erased_chunks(dev);
++ int chunks_after;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
++
++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d, in use %d, shrink %d, whole_block %d",
++ block, bi->pages_in_use, bi->has_shrink_hdr,
++ whole_block);
++
++ /*yaffs_verify_free_chunks(dev); */
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
++
++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
++
++ dev->gc_disable = 1;
++
++ yaffs_summary_gc(dev, block);
++
++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "Collecting block %d that has no chunks in use",
++ block);
++ yaffs_block_became_dirty(dev, block);
++ } else {
++
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_verify_blk(dev, bi, block);
++
++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
++
++ for (/* init already done */ ;
++ ret_val == YAFFS_OK &&
++ dev->gc_chunk < dev->param.chunks_per_block &&
++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
++ max_copies > 0;
++ dev->gc_chunk++, old_chunk++) {
++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
++ /* Page is in use and might need to be copied */
++ max_copies--;
++ ret_val = yaffs_gc_process_chunk(dev, bi,
++ old_chunk, buffer);
++ }
++ }
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ yaffs_verify_collected_blk(dev, bi, block);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ /*
++ * The gc did not complete. Set block state back to FULL
++ * because checkpointing does not restore gc.
++ */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ } else {
++ /* The gc completed. */
++ /* Do any required cleanups */
++ for (i = 0; i < dev->n_clean_ups; i++) {
++ /* Time to delete the file too */
++ struct yaffs_obj *object =
++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
++ if (object) {
++ yaffs_free_tnode(dev,
++ object->variant.file_variant.top);
++ object->variant.file_variant.top = NULL;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: About to finally delete object %d",
++ object->obj_id);
++ yaffs_generic_obj_del(object);
++ object->my_dev->n_deleted_files--;
++ }
++
++ }
++ chunks_after = yaffs_get_erased_chunks(dev);
++ if (chunks_before >= chunks_after)
++ yaffs_trace(YAFFS_TRACE_GC,
++ "gc did not increase free chunks before %d after %d",
++ chunks_before, chunks_after);
++ dev->gc_block = 0;
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ dev->gc_disable = 0;
++
++ return ret_val;
++}
++
++/*
++ * find_gc_block() selects the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
++ int aggressive, int background)
++{
++ int i;
++ int iterations;
++ unsigned selected = 0;
++ int prioritised = 0;
++ int prioritised_exist = 0;
++ struct yaffs_block_info *bi;
++ int threshold;
++
++ /* First let's see if we need to grab a prioritised block */
++ if (dev->has_pending_prioritised_gc && !aggressive) {
++ dev->gc_dirtiest = 0;
++ bi = dev->block_info;
++ for (i = dev->internal_start_block;
++ i <= dev->internal_end_block && !selected; i++) {
++
++ if (bi->gc_prioritise) {
++ prioritised_exist = 1;
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ selected = i;
++ prioritised = 1;
++ }
++ }
++ bi++;
++ }
++
++ /*
++ * If there is a prioritised block and none was selected then
++ * this happened because there is at least one old dirty block
++ * gumming up the works. Let's gc the oldest dirty block.
++ */
++
++ if (prioritised_exist &&
++ !selected && dev->oldest_dirty_block > 0)
++ selected = dev->oldest_dirty_block;
++
++ if (!prioritised_exist) /* None found, so we can clear this */
++ dev->has_pending_prioritised_gc = 0;
++ }
++
++ /* If we're doing aggressive GC then we are happy to take a less-dirty
++ * block, and search harder.
++ * else (leasurely gc), then we only bother to do this if the
++ * block has only a few pages in use.
++ */
++
++ if (!selected) {
++ int pages_used;
++ int n_blocks =
++ dev->internal_end_block - dev->internal_start_block + 1;
++ if (aggressive) {
++ threshold = dev->param.chunks_per_block;
++ iterations = n_blocks;
++ } else {
++ int max_threshold;
++
++ if (background)
++ max_threshold = dev->param.chunks_per_block / 2;
++ else
++ max_threshold = dev->param.chunks_per_block / 8;
++
++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++
++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++ if (threshold > max_threshold)
++ threshold = max_threshold;
++
++ iterations = n_blocks / 16 + 1;
++ if (iterations > 100)
++ iterations = 100;
++ }
++
++ for (i = 0;
++ i < iterations &&
++ (dev->gc_dirtiest < 1 ||
++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
++ i++) {
++ dev->gc_block_finder++;
++ if (dev->gc_block_finder < dev->internal_start_block ||
++ dev->gc_block_finder > dev->internal_end_block)
++ dev->gc_block_finder =
++ dev->internal_start_block;
++
++ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
++
++ pages_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ pages_used < dev->param.chunks_per_block &&
++ (dev->gc_dirtiest < 1 ||
++ pages_used < dev->gc_pages_in_use) &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ dev->gc_dirtiest = dev->gc_block_finder;
++ dev->gc_pages_in_use = pages_used;
++ }
++ }
++
++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
++ selected = dev->gc_dirtiest;
++ }
++
++ /*
++ * If nothing has been selected for a while, try the oldest dirty
++ * because that's gumming up the works.
++ */
++
++ if (!selected && dev->param.is_yaffs2 &&
++ dev->gc_not_done >= (background ? 10 : 20)) {
++ yaffs2_find_oldest_dirty_seq(dev);
++ if (dev->oldest_dirty_block > 0) {
++ selected = dev->oldest_dirty_block;
++ dev->gc_dirtiest = selected;
++ dev->oldest_dirty_gc_count++;
++ bi = yaffs_get_block_info(dev, selected);
++ dev->gc_pages_in_use =
++ bi->pages_in_use - bi->soft_del_pages;
++ } else {
++ dev->gc_not_done = 0;
++ }
++ }
++
++ if (selected) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC Selected block %d with %d free, prioritised:%d",
++ selected,
++ dev->param.chunks_per_block - dev->gc_pages_in_use,
++ prioritised);
++
++ dev->n_gc_blocks++;
++ if (background)
++ dev->bg_gcs++;
++
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ dev->gc_not_done = 0;
++ if (dev->refresh_skip > 0)
++ dev->refresh_skip--;
++ } else {
++ dev->gc_not_done++;
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
++ dev->gc_block_finder, dev->gc_not_done, threshold,
++ dev->gc_dirtiest, dev->gc_pages_in_use,
++ dev->oldest_dirty_block, background ? " bg" : "");
++ }
++
++ return selected;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_check_gc(struct yaffs_dev *dev, int background)
++{
++ int aggressive = 0;
++ int gc_ok = YAFFS_OK;
++ int max_tries = 0;
++ int min_erased;
++ int erased_chunks;
++ int checkpt_block_adjust;
++
++ if (dev->param.gc_control_fn &&
++ (dev->param.gc_control_fn(dev) & 1) == 0)
++ return YAFFS_OK;
++
++ if (dev->gc_disable)
++ /* Bail out so we don't get recursive gc */
++ return YAFFS_OK;
++
++ /* This loop should pass the first time.
++ * Only loops here if the collection does not increase space.
++ */
++
++ do {
++ max_tries++;
++
++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
++
++ min_erased =
++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
++ erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ /* If we need a block soon then do aggressive gc. */
++ if (dev->n_erased_blocks < min_erased)
++ aggressive = 1;
++ else {
++ if (!background
++ && erased_chunks > (dev->n_free_chunks / 4))
++ break;
++
++ if (dev->gc_skip > 20)
++ dev->gc_skip = 20;
++ if (erased_chunks < dev->n_free_chunks / 2 ||
++ dev->gc_skip < 1 || background)
++ aggressive = 0;
++ else {
++ dev->gc_skip--;
++ break;
++ }
++ }
++
++ dev->gc_skip = 5;
++
++ /* If we don't already have a block being gc'd then see if we
++ * should start another */
++
++ if (dev->gc_block < 1 && !aggressive) {
++ dev->gc_block = yaffs2_find_refresh_block(dev);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++ if (dev->gc_block < 1) {
++ dev->gc_block =
++ yaffs_find_gc_block(dev, aggressive, background);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ if (dev->gc_block > 0) {
++ dev->all_gcs++;
++ if (!aggressive)
++ dev->passive_gc_count++;
++
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC n_erased_blocks %d aggressive %d",
++ dev->n_erased_blocks, aggressive);
++
++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
++ }
++
++ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
++ dev->gc_block > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
++ dev->n_erased_blocks, max_tries,
++ dev->gc_block);
++ }
++ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
++ (dev->gc_block > 0) && (max_tries < 2));
++
++ return aggressive ? gc_ok : YAFFS_OK;
++}
++
++/*
++ * yaffs_bg_gc()
++ * Garbage collects. Intended to be called from a background thread.
++ * Returns non-zero if at least half the free chunks are erased.
++ */
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
++{
++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
++
++ yaffs_check_gc(dev, 1);
++ return erased_chunks > dev->n_free_chunks / 2;
++}
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
++{
++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
++
++ if (nand_chunk >= 0)
++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
++ buffer, NULL);
++ else {
++ yaffs_trace(YAFFS_TRACE_NANDACCESS,
++ "Chunk %d not found zero instead",
++ nand_chunk);
++ /* get sane (zero) data if you read a hole */
++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
++ return 0;
++ }
++
++}
++
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn)
++{
++ int block;
++ int page;
++ struct yaffs_ext_tags tags;
++ struct yaffs_block_info *bi;
++
++ if (chunk_id <= 0)
++ return;
++
++ dev->n_deletions++;
++ block = chunk_id / dev->param.chunks_per_block;
++ page = chunk_id % dev->param.chunks_per_block;
++
++ if (!yaffs_check_chunk_bit(dev, block, page))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Deleting invalid chunk %d", chunk_id);
++
++ bi = yaffs_get_block_info(dev, block);
++
++ yaffs2_update_oldest_dirty_seq(dev, block, bi);
++
++ yaffs_trace(YAFFS_TRACE_DELETION,
++ "line %d delete of chunk %d",
++ lyn, chunk_id);
++
++ if (!dev->param.is_yaffs2 && mark_flash &&
++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
++
++ memset(&tags, 0, sizeof(tags));
++ tags.is_deleted = 1;
++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
++ yaffs_handle_chunk_update(dev, chunk_id, &tags);
++ } else {
++ dev->n_unmarked_deletions++;
++ }
++
++ /* Pull out of the management area.
++ * If the whole block became dirty, this will kick off an erasure.
++ */
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
++ bi->block_state == YAFFS_BLOCK_STATE_FULL ||
++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->n_free_chunks++;
++ yaffs_clear_chunk_bit(dev, block, page);
++ bi->pages_in_use--;
++
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ yaffs_block_became_dirty(dev, block);
++ }
++ }
++}
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 *buffer, int n_bytes, int use_reserve)
++{
++ /* Find old chunk Need to do this to get serial number
++ * Write new one and patch into tree.
++ * Invalidate old tags.
++ */
++
++ int prev_chunk_id;
++ struct yaffs_ext_tags prev_tags;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_dev *dev = in->my_dev;
++
++ yaffs_check_gc(dev, 0);
++
++ /* Get the previous chunk at this location in the file if it exists.
++ * If it does not exist then put a zero into the tree. This creates
++ * the tnode now, rather than later when it is harder to clean up.
++ */
++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
++ if (prev_chunk_id < 1 &&
++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
++ return 0;
++
++ /* Set up new tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++
++ new_tags.chunk_id = inode_chunk;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number =
++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
++ new_tags.n_bytes = n_bytes;
++
++ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Writing %d bytes to chunk!!!!!!!!!",
++ n_bytes);
++ BUG();
++ }
++
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
++
++ if (new_chunk_id > 0) {
++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ yaffs_verify_file_sane(in);
++ }
++ return new_chunk_id;
++
++}
++
++
++
++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
++ const YCHAR *name, const void *value, int size,
++ int flags)
++{
++ struct yaffs_xattr_mod xmod;
++ int result;
++
++ xmod.set = set;
++ xmod.name = name;
++ xmod.data = value;
++ xmod.size = size;
++ xmod.flags = flags;
++ xmod.result = -ENOSPC;
++
++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
++
++ if (result > 0)
++ return xmod.result;
++ else
++ return -ENOSPC;
++}
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++ struct yaffs_xattr_mod *xmod)
++{
++ int retval = 0;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer = buffer + x_offs;
++
++ if (xmod->set)
++ retval =
++ nval_set(x_buffer, x_size, xmod->name, xmod->data,
++ xmod->size, xmod->flags);
++ else
++ retval = nval_del(x_buffer, x_size, xmod->name);
++
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ xmod->result = retval;
++
++ return retval;
++}
++
++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
++ void *value, int size)
++{
++ char *buffer = NULL;
++ int result;
++ struct yaffs_ext_tags tags;
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++ char *x_buffer;
++ int retval = 0;
++
++ if (obj->hdr_chunk < 1)
++ return -ENODATA;
++
++ /* If we know that the object has no xattribs then don't do all the
++ * reading and parsing.
++ */
++ if (obj->xattr_known && !obj->has_xattr) {
++ if (name)
++ return -ENODATA;
++ else
++ return 0;
++ }
++
++ buffer = (char *)yaffs_get_temp_buffer(dev);
++ if (!buffer)
++ return -ENOMEM;
++
++ result =
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
++
++ if (result != YAFFS_OK)
++ retval = -ENOENT;
++ else {
++ x_buffer = buffer + x_offs;
++
++ if (!obj->xattr_known) {
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ }
++
++ if (name)
++ retval = nval_get(x_buffer, x_size, name, value, size);
++ else
++ retval = nval_list(x_buffer, x_size, value, size);
++ }
++ yaffs_release_temp_buffer(dev, (u8 *) buffer);
++ return retval;
++}
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++ const void *value, int size, int flags)
++{
++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
++}
++
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
++{
++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
++}
++
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++ int size)
++{
++ return yaffs_do_xattrib_fetch(obj, name, value, size);
++}
++
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
++{
++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
++}
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
++{
++ u8 *buf;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++
++ if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
++ return;
++
++ dev = in->my_dev;
++ in->lazy_loaded = 0;
++ buf = yaffs_get_temp_buffer(dev);
++
++ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
++ oh = (struct yaffs_obj_hdr *)buf;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ yaffs_set_obj_name_from_oh(in, oh);
++
++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ in->variant.symlink_variant.alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.symlink_variant.alias)
++ alloc_failed = 1; /* Not returned */
++ }
++ yaffs_release_temp_buffer(dev, buf);
++}
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
++ const YCHAR *oh_name, int buff_size)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ if (dev->param.auto_unicode) {
++ if (*oh_name) {
++ /* It is an ASCII name, do an ASCII to
++ * unicode conversion */
++ const char *ascii_oh_name = (const char *)oh_name;
++ int n = buff_size - 1;
++ while (n > 0 && *ascii_oh_name) {
++ *name = *ascii_oh_name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ strncpy(name, oh_name + 1, buff_size - 1);
++ }
++ } else {
++#else
++ (void) dev;
++ {
++#endif
++ strncpy(name, oh_name, buff_size - 1);
++ }
++}
++
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
++ const YCHAR *name)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++
++ int is_ascii;
++ YCHAR *w;
++
++ if (dev->param.auto_unicode) {
++
++ is_ascii = 1;
++ w = name;
++
++ /* Figure out if the name will fit in ascii character set */
++ while (is_ascii && *w) {
++ if ((*w) & 0xff00)
++ is_ascii = 0;
++ w++;
++ }
++
++ if (is_ascii) {
++ /* It is an ASCII name, so convert unicode to ascii */
++ char *ascii_oh_name = (char *)oh_name;
++ int n = YAFFS_MAX_NAME_LENGTH - 1;
++ while (n > 0 && *name) {
++ *ascii_oh_name = *name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ /* Unicode name, so save starting at the second YCHAR */
++ *oh_name = 0;
++ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
++ }
++ } else {
++#else
++ dev = dev;
++ {
++#endif
++ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
++ }
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
++{
++
++ struct yaffs_block_info *bi;
++ struct yaffs_dev *dev = in->my_dev;
++ int prev_chunk_id;
++ int ret_val = 0;
++ int result = 0;
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_ext_tags old_tags;
++ const YCHAR *alias = NULL;
++ u8 *buffer = NULL;
++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj_hdr *oh = NULL;
++ loff_t file_size = 0;
++
++ strcpy(old_name, _Y("silly old name"));
++
++ if (in->fake && in != dev->root_dir && !force && !xmod)
++ return ret_val;
++
++ yaffs_check_gc(dev, 0);
++ yaffs_check_obj_details_loaded(in);
++
++ buffer = yaffs_get_temp_buffer(in->my_dev);
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ prev_chunk_id = in->hdr_chunk;
++
++ if (prev_chunk_id > 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
++ buffer, &old_tags);
++
++ yaffs_verify_oh(in, oh, &old_tags, 0);
++ memcpy(old_name, oh->name, sizeof(oh->name));
++ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
++ } else {
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ }
++
++ oh->type = in->variant_type;
++ oh->yst_mode = in->yst_mode;
++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
++
++ yaffs_load_attribs_oh(oh, in);
++
++ if (in->parent)
++ oh->parent_obj_id = in->parent->obj_id;
++ else
++ oh->parent_obj_id = 0;
++
++ if (name && *name) {
++ memset(oh->name, 0, sizeof(oh->name));
++ yaffs_load_oh_from_name(dev, oh->name, name);
++ } else if (prev_chunk_id > 0) {
++ memcpy(oh->name, old_name, sizeof(oh->name));
++ } else {
++ memset(oh->name, 0, sizeof(oh->name));
++ }
++
++ oh->is_shrink = is_shrink;
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Should not happen */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
++ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
++ file_size = in->variant.file_variant.file_size;
++ yaffs_oh_size_load(oh, file_size);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = in->variant.symlink_variant.alias;
++ if (!alias)
++ alias = _Y("no alias");
++ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++ break;
++ }
++
++ /* process any xattrib modifications */
++ if (xmod)
++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
++
++ /* Tags */
++ memset(&new_tags, 0, sizeof(new_tags));
++ in->serial++;
++ new_tags.chunk_id = 0;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number = in->serial;
++
++ /* Add extra info for file header */
++ new_tags.extra_available = 1;
++ new_tags.extra_parent_id = oh->parent_obj_id;
++ new_tags.extra_file_size = file_size;
++ new_tags.extra_is_shrink = oh->is_shrink;
++ new_tags.extra_equiv_id = oh->equiv_id;
++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
++ new_tags.extra_obj_type = in->variant_type;
++ yaffs_verify_oh(in, oh, &new_tags, 1);
++
++ /* Create new chunk in NAND */
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags,
++ (prev_chunk_id > 0) ? 1 : 0);
++
++ if (buffer)
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (new_chunk_id < 0)
++ return new_chunk_id;
++
++ in->hdr_chunk = new_chunk_id;
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ if (!yaffs_obj_cache_dirty(in))
++ in->dirty = 0;
++
++ /* If this was a shrink, then mark the block
++ * that the chunk lives on */
++ if (is_shrink) {
++ bi = yaffs_get_block_info(in->my_dev,
++ new_chunk_id /
++ in->my_dev->param.chunks_per_block);
++ bi->has_shrink_hdr = 1;
++ }
++
++
++ return new_chunk_id;
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
++{
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ struct yaffs_cache *cache;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++ if ((start + n) < dev->data_bytes_per_chunk)
++ n_copy = n;
++ else
++ n_copy = dev->data_bytes_per_chunk - start;
++
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ /* If the chunk is already in the cache or it is less than
++ * a whole chunk or we're using inband tags then use the cache
++ * (if there is caching) else bypass the cache.
++ */
++ if (cache || n_copy != dev->data_bytes_per_chunk ||
++ dev->param.inband_tags) {
++ if (dev->param.n_caches > 0) {
++
++ /* If we can't find the data in the cache,
++ * then load it up. */
++
++ if (!cache) {
++ cache =
++ yaffs_grab_chunk_cache(in->my_dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ cache->n_bytes = 0;
++ }
++
++ yaffs_use_cache(dev, cache, 0);
++
++ cache->locked = 1;
++
++ memcpy(buffer, &cache->data[start], n_copy);
++
++ cache->locked = 0;
++ } else {
++ /* Read into the local buffer then copy.. */
++
++ u8 *local_buffer =
++ yaffs_get_temp_buffer(dev);
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++
++ memcpy(buffer, &local_buffer[start], n_copy);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Read directly into the buffer. */
++ yaffs_rd_data_obj(in, chunk, buffer);
++ }
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ return n_done;
++}
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ int n_writeback;
++ loff_t start_write = offset;
++ int chunk_written = 0;
++ u32 n_bytes_read;
++ loff_t chunk_start;
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0 && chunk_written >= 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++
++ if (((loff_t)chunk) *
++ dev->data_bytes_per_chunk + start != offset ||
++ start >= dev->data_bytes_per_chunk) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "AddrToChunk of offset %lld gives chunk %d start %d",
++ offset, chunk, start);
++ }
++ chunk++; /* File pos to chunk in file offset */
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++
++ if ((start + n) < dev->data_bytes_per_chunk) {
++ n_copy = n;
++
++ /* Now calculate how many bytes to write back....
++ * If we're overwriting and not writing to then end of
++ * file then we need to write back as much as was there
++ * before.
++ */
++
++ chunk_start = (((loff_t)(chunk - 1)) *
++ dev->data_bytes_per_chunk);
++
++ if (chunk_start > in->variant.file_variant.file_size)
++ n_bytes_read = 0; /* Past end of file */
++ else
++ n_bytes_read =
++ in->variant.file_variant.file_size -
++ chunk_start;
++
++ if (n_bytes_read > dev->data_bytes_per_chunk)
++ n_bytes_read = dev->data_bytes_per_chunk;
++
++ n_writeback =
++ (n_bytes_read >
++ (start + n)) ? n_bytes_read : (start + n);
++
++ if (n_writeback < 0 ||
++ n_writeback > dev->data_bytes_per_chunk)
++ BUG();
++
++ } else {
++ n_copy = dev->data_bytes_per_chunk - start;
++ n_writeback = dev->data_bytes_per_chunk;
++ }
++
++ if (n_copy != dev->data_bytes_per_chunk ||
++ !dev->param.cache_bypass_aligned ||
++ dev->param.inband_tags) {
++ /* An incomplete start or end chunk (or maybe both
++ * start and end chunk), or we're using inband tags,
++ * or we're forcing writes through the cache,
++ * so we want to use the cache buffers.
++ */
++ if (dev->param.n_caches > 0) {
++ struct yaffs_cache *cache;
++
++ /* If we can't find the data in the cache, then
++ * load the cache */
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ if (!cache &&
++ yaffs_check_alloc_available(dev, 1)) {
++ cache = yaffs_grab_chunk_cache(dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ } else if (cache &&
++ !cache->dirty &&
++ !yaffs_check_alloc_available(dev,
++ 1)) {
++ /* Drop the cache if it was a read cache
++ * item and no space check has been made
++ * for it.
++ */
++ cache = NULL;
++ }
++
++ if (cache) {
++ yaffs_use_cache(dev, cache, 1);
++ cache->locked = 1;
++
++ memcpy(&cache->data[start], buffer,
++ n_copy);
++
++ cache->locked = 0;
++ cache->n_bytes = n_writeback;
++
++ if (write_through) {
++ chunk_written =
++ yaffs_wr_data_obj
++ (cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ }
++ } else {
++ chunk_written = -1; /* fail write */
++ }
++ } else {
++ /* An incomplete start or end chunk (or maybe
++ * both start and end chunk). Read into the
++ * local buffer then copy over and write back.
++ */
++
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++ memcpy(&local_buffer[start], buffer, n_copy);
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk,
++ local_buffer,
++ n_writeback, 0);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++ } else {
++ /* A full chunk. Write directly from the buffer. */
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk, buffer,
++ dev->data_bytes_per_chunk, 0);
++
++ /* Since we've overwritten the cached data,
++ * we better invalidate it. */
++ yaffs_invalidate_chunk_cache(in, chunk);
++ }
++
++ if (chunk_written >= 0) {
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++ }
++
++ /* Update file object */
++
++ if ((start_write + n_done) > in->variant.file_variant.file_size)
++ in->variant.file_variant.file_size = (start_write + n_done);
++
++ in->dirty = 1;
++ return n_done;
++}
++
++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_through)
++{
++ yaffs2_handle_hole(in, offset);
++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
++}
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
++{
++
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++ int i;
++ int chunk_id;
++ u32 dummy;
++ int last_del;
++ int start_del;
++
++ if (old_size > 0)
++ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
++ else
++ last_del = 0;
++
++ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
++ &start_del, &dummy);
++ last_del++;
++ start_del++;
++
++ /* Delete backwards so that we don't end up with holes if
++ * power is lost part-way through the operation.
++ */
++ for (i = last_del; i >= start_del; i--) {
++ /* NB this could be optimised somewhat,
++ * eg. could retrieve the tags and write them without
++ * using yaffs_chunk_del
++ */
++
++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
++
++ if (chunk_id < 1)
++ continue;
++
++ if (chunk_id <
++ (dev->internal_start_block * dev->param.chunks_per_block) ||
++ chunk_id >=
++ ((dev->internal_end_block + 1) *
++ dev->param.chunks_per_block)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Found daft chunk_id %d for %d",
++ chunk_id, i);
++ } else {
++ in->n_data_chunks--;
++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
++ }
++ }
++}
++
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
++{
++ int new_full;
++ u32 new_partial;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
++
++ yaffs_prune_chunks(obj, new_size);
++
++ if (new_partial != 0) {
++ int last_chunk = 1 + new_full;
++ u8 *local_buffer = yaffs_get_temp_buffer(dev);
++
++ /* Rewrite the last chunk with its new size and zero pad */
++ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
++ memset(local_buffer + new_partial, 0,
++ dev->data_bytes_per_chunk - new_partial);
++
++ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
++ new_partial, 1);
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++ }
++
++ obj->variant.file_variant.file_size = new_size;
++
++ yaffs_prune_tree(dev, &obj->variant.file_variant);
++}
++
++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
++{
++ struct yaffs_dev *dev = in->my_dev;
++ loff_t old_size = in->variant.file_variant.file_size;
++
++ yaffs_flush_file_cache(in);
++ yaffs_invalidate_whole_cache(in);
++
++ yaffs_check_gc(dev, 0);
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ if (new_size == old_size)
++ return YAFFS_OK;
++
++ if (new_size > old_size) {
++ yaffs2_handle_hole(in, new_size);
++ in->variant.file_variant.file_size = new_size;
++ } else {
++ /* new_size < old_size */
++ yaffs_resize_file_down(in, new_size);
++ }
++
++ /* Write a new object header to reflect the resize.
++ * show we've shrunk the file, if need be
++ * Do this only if the file is not in the deleted directories
++ * and is not shadowed.
++ */
++ if (in->parent &&
++ !in->is_shadowed &&
++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ in->parent->obj_id != YAFFS_OBJECTID_DELETED)
++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
++
++ return YAFFS_OK;
++}
++
++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
++{
++ if (!in->dirty)
++ return YAFFS_OK;
++
++ yaffs_flush_file_cache(in);
++
++ if (data_sync)
++ return YAFFS_OK;
++
++ if (update_time)
++ yaffs_load_current_time(in, 0, 0);
++
++ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
++ YAFFS_OK : YAFFS_FAIL;
++}
++
++
++/* yaffs_del_file deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
++{
++ int ret_val;
++ int del_now = 0;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!in->my_inode)
++ del_now = 1;
++
++ if (del_now) {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->del_dir,
++ _Y("deleted"), 0, 0);
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: immediate deletion of file %d",
++ in->obj_id);
++ in->deleted = 1;
++ in->my_dev->n_deleted_files++;
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++ yaffs_soft_del_file(in);
++ } else {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++ return ret_val;
++}
++
++static int yaffs_del_file(struct yaffs_obj *in)
++{
++ int ret_val = YAFFS_OK;
++ int deleted; /* Need to cache value on stack if in is freed */
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++
++ if (in->n_data_chunks > 0) {
++ /* Use soft deletion if there is data in the file.
++ * That won't be the case if it has been resized to zero.
++ */
++ if (!in->unlinked)
++ ret_val = yaffs_unlink_file_if_needed(in);
++
++ deleted = in->deleted;
++
++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
++ in->deleted = 1;
++ deleted = 1;
++ in->my_dev->n_deleted_files++;
++ yaffs_soft_del_file(in);
++ }
++ return deleted ? YAFFS_OK : YAFFS_FAIL;
++ } else {
++ /* The file has no data chunks so we toss it immediately */
++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
++ in->variant.file_variant.top = NULL;
++ yaffs_generic_obj_del(in);
++
++ return YAFFS_OK;
++ }
++}
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
++{
++ return (obj &&
++ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++ !(list_empty(&obj->variant.dir_variant.children));
++}
++
++static int yaffs_del_dir(struct yaffs_obj *obj)
++{
++ /* First check that the directory is empty. */
++ if (yaffs_is_non_empty_dir(obj))
++ return YAFFS_FAIL;
++
++ return yaffs_generic_obj_del(obj);
++}
++
++static int yaffs_del_symlink(struct yaffs_obj *in)
++{
++ kfree(in->variant.symlink_variant.alias);
++ in->variant.symlink_variant.alias = NULL;
++
++ return yaffs_generic_obj_del(in);
++}
++
++static int yaffs_del_link(struct yaffs_obj *in)
++{
++ /* remove this hardlink from the list associated with the equivalent
++ * object
++ */
++ list_del_init(&in->hard_links);
++ return yaffs_generic_obj_del(in);
++}
++
++int yaffs_del_obj(struct yaffs_obj *obj)
++{
++ int ret_val = -1;
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ ret_val = yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!list_empty(&obj->variant.dir_variant.dirty)) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "Remove object %d from dirty directories",
++ obj->obj_id);
++ list_del_init(&obj->variant.dir_variant.dirty);
++ }
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ ret_val = yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ ret_val = yaffs_del_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ ret_val = yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ ret_val = 0;
++ break; /* should not happen. */
++ }
++ return ret_val;
++}
++
++
++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
++ struct yaffs_obj *to_dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_add_obj_to_dir(to_dir, obj);
++ }
++}
++
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type)
++{
++ /* Tear down the old variant */
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ /* Nuke file data */
++ yaffs_resize_file(obj, 0);
++ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Put the children in lost and found. */
++ yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
++ if (!list_empty(&obj->variant.dir_variant.dirty))
++ list_del_init(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ /* Nuke symplink data */
++ kfree(obj->variant.symlink_variant.alias);
++ obj->variant.symlink_variant.alias = NULL;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ list_del_init(&obj->hard_links);
++ break;
++ default:
++ break;
++ }
++
++ memset(&obj->variant, 0, sizeof(obj->variant));
++
++ /*Set up new variant if the memset is not enough. */
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ default:
++ break;
++ }
++
++ obj->variant_type = type;
++
++ return obj;
++
++}
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj)
++{
++ int del_now = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (!obj->my_inode)
++ del_now = 1;
++
++ yaffs_update_parent(obj->parent);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ return yaffs_del_link(obj);
++ } else if (!list_empty(&obj->hard_links)) {
++ /* Curve ball: We're unlinking an object that has a hardlink.
++ *
++ * This problem arises because we are not strictly following
++ * The Linux link/inode model.
++ *
++ * We can't really delete the object.
++ * Instead, we do the following:
++ * - Select a hardlink.
++ * - Unhook it from the hard links
++ * - Move it from its parent directory so that the rename works.
++ * - Rename the object to the hardlink's name.
++ * - Delete the hardlink
++ */
++
++ struct yaffs_obj *hl;
++ struct yaffs_obj *parent;
++ int ret_val;
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
++ hard_links);
++
++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++ parent = hl->parent;
++
++ list_del_init(&hl->hard_links);
++
++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
++
++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
++
++ if (ret_val == YAFFS_OK)
++ ret_val = yaffs_generic_obj_del(hl);
++
++ return ret_val;
++
++ } else if (del_now) {
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ list_del_init(&obj->variant.dir_variant.dirty);
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ return yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ return YAFFS_FAIL;
++ }
++ } else if (yaffs_is_non_empty_dir(obj)) {
++ return YAFFS_FAIL;
++ } else {
++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++}
++
++static int yaffs_unlink_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->unlink_allowed)
++ return yaffs_unlink_worker(obj);
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
++{
++ struct yaffs_obj *obj;
++
++ obj = yaffs_find_by_name(dir, name);
++ return yaffs_unlink_obj(obj);
++}
++
++/* Note:
++ * If old_name is NULL then we take old_dir as the object to be renamed.
++ */
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
++ struct yaffs_obj *new_dir, const YCHAR *new_name)
++{
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *existing_target = NULL;
++ int force = 0;
++ int result;
++ struct yaffs_dev *dev;
++
++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ dev = old_dir->my_dev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ /* Special case for case insemsitive systems.
++ * While look-up is case insensitive, the name isn't.
++ * Therefore we might want to change x.txt to X.txt
++ */
++ if (old_dir == new_dir &&
++ old_name && new_name &&
++ strcmp(old_name, new_name) == 0)
++ force = 1;
++#endif
++
++ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ /* ENAMETOOLONG */
++ return YAFFS_FAIL;
++
++ if (old_name)
++ obj = yaffs_find_by_name(old_dir, old_name);
++ else{
++ obj = old_dir;
++ old_dir = obj->parent;
++ }
++
++ if (obj && obj->rename_allowed) {
++ /* Now handle an existing target, if there is one */
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++ if (yaffs_is_non_empty_dir(existing_target)) {
++ return YAFFS_FAIL; /* ENOTEMPTY */
++ } else if (existing_target && existing_target != obj) {
++ /* Nuke the target first, using shadowing,
++ * but only if it isn't the same object.
++ *
++ * Note we must disable gc here otherwise it can mess
++ * up the shadowing.
++ *
++ */
++ dev->gc_disable = 1;
++ yaffs_change_obj_name(obj, new_dir, new_name, force,
++ existing_target->obj_id);
++ existing_target->is_shadowed = 1;
++ yaffs_unlink_obj(existing_target);
++ dev->gc_disable = 0;
++ }
++
++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
++
++ yaffs_update_parent(old_dir);
++ if (new_dir != old_dir)
++ yaffs_update_parent(new_dir);
++
++ return result;
++ }
++ return YAFFS_FAIL;
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning)
++{
++ struct yaffs_obj *obj;
++
++ if (backward_scanning) {
++ /* Handle YAFFS2 case (backward scanning)
++ * If the shadowed object exists then ignore.
++ */
++ obj = yaffs_find_by_number(dev, obj_id);
++ if (obj)
++ return;
++ }
++
++ /* Let's create it (if it does not exist) assuming it is a file so that
++ * it can do shrinking etc.
++ * We put it in unlinked dir to be cleaned up after the scanning
++ */
++ obj =
++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
++ if (!obj)
++ return;
++ obj->is_shadowed = 1;
++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
++ obj->variant.file_variant.shrink_size = 0;
++ obj->valid = 1; /* So that we don't read any other info. */
++}
++
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
++{
++ struct list_head *lh;
++ struct list_head *save;
++ struct yaffs_obj *hl;
++ struct yaffs_obj *in;
++
++ list_for_each_safe(lh, save, hard_list) {
++ hl = list_entry(lh, struct yaffs_obj, hard_links);
++ in = yaffs_find_by_number(dev,
++ hl->variant.hardlink_variant.equiv_id);
++
++ if (in) {
++ /* Add the hardlink pointers */
++ hl->variant.hardlink_variant.equiv_obj = in;
++ list_add(&hl->hard_links, &in->hard_links);
++ } else {
++ /* Todo Need to report/handle this better.
++ * Got a problem... hardlink to a non-existant object
++ */
++ hl->variant.hardlink_variant.equiv_obj = NULL;
++ INIT_LIST_HEAD(&hl->hard_links);
++ }
++ }
++}
++
++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
++{
++ /*
++ * Sort out state of unlinked and deleted objects after scanning.
++ */
++ struct list_head *i;
++ struct list_head *n;
++ struct yaffs_obj *l;
++
++ if (dev->read_only)
++ return;
++
++ /* Soft delete all the unlinked files */
++ list_for_each_safe(i, n,
++ &dev->unlinked_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++
++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ * This code assumes that we don't ever change the current relationships
++ * between directories:
++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
++ * lost-n-found->parent == root_dir
++ *
++ * This fixes the problem where directories might have inadvertently been
++ * deleted leaving the object "hanging" without being rooted in the
++ * directory tree.
++ */
++
++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++ return (obj == dev->del_dir ||
++ obj == dev->unlinked_dir || obj == dev->root_dir);
++}
++
++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_obj *parent;
++ int i;
++ struct list_head *lh;
++ struct list_head *n;
++ int depth_limit;
++ int hanging;
++
++ if (dev->read_only)
++ return;
++
++ /* Iterate through the objects in each hash entry,
++ * looking at each object.
++ * Make sure it is rooted.
++ */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ parent = obj->parent;
++
++ if (yaffs_has_null_parent(dev, obj)) {
++ /* These directories are not hanging */
++ hanging = 0;
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ hanging = 1;
++ } else if (yaffs_has_null_parent(dev, parent)) {
++ hanging = 0;
++ } else {
++ /*
++ * Need to follow the parent chain to
++ * see if it is hanging.
++ */
++ hanging = 0;
++ depth_limit = 100;
++
++ while (parent != dev->root_dir &&
++ parent->parent &&
++ parent->parent->variant_type ==
++ YAFFS_OBJECT_TYPE_DIRECTORY &&
++ depth_limit > 0) {
++ parent = parent->parent;
++ depth_limit--;
++ }
++ if (parent != dev->root_dir)
++ hanging = 1;
++ }
++ if (hanging) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Hanging object %d moved to lost and found",
++ obj->obj_id);
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++ }
++ }
++ }
++}
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_del_dir_contents(struct yaffs_obj *dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ BUG();
++
++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
++ yaffs_del_dir_contents(obj);
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Deleting lost_found object %d",
++ obj->obj_id);
++ yaffs_unlink_obj(obj);
++ }
++}
++
++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
++{
++ yaffs_del_dir_contents(dev->lost_n_found);
++}
++
++
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
++ const YCHAR *name)
++{
++ int sum;
++ struct list_head *i;
++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++ struct yaffs_obj *l;
++
++ if (!name)
++ return NULL;
++
++ if (!directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: null pointer directory"
++ );
++ BUG();
++ return NULL;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "tragedy: yaffs_find_by_name: non-directory"
++ );
++ BUG();
++ }
++
++ sum = yaffs_calc_name_sum(name);
++
++ list_for_each(i, &directory->variant.dir_variant.children) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++
++ if (l->parent != directory)
++ BUG();
++
++ yaffs_check_obj_details_loaded(l);
++
++ /* Special case for lost-n-found */
++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
++ return l;
++ } else if (l->sum == sum || l->hdr_chunk <= 0) {
++ /* LostnFound chunk called Objxxx
++ * Do a real check
++ */
++ yaffs_get_obj_name(l, buffer,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
++ return l;
++ }
++ }
++ return NULL;
++}
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ obj = obj->variant.hardlink_variant.equiv_obj;
++ yaffs_check_obj_details_loaded(obj);
++ }
++ return obj;
++}
++
++/*
++ * A note or two on object names.
++ * * If the object name is missing, we then make one up in the form objnnn
++ *
++ * * ASCII names are stored in the object header's name field from byte zero
++ * * Unicode names are historically stored starting from byte zero.
++ *
++ * Then there are automatic Unicode names...
++ * The purpose of these is to save names in a way that can be read as
++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
++ * system to share files.
++ *
++ * These automatic unicode are stored slightly differently...
++ * - If the name can fit in the ASCII character space then they are saved as
++ * ascii names as per above.
++ * - If the name needs Unicode then the name is saved in Unicode
++ * starting at oh->name[1].
++
++ */
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++ int buffer_size)
++{
++ /* Create an object name if we could not find one. */
++ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
++ YCHAR local_name[20];
++ YCHAR num_string[20];
++ YCHAR *x = &num_string[19];
++ unsigned v = obj->obj_id;
++ num_string[19] = 0;
++ while (v > 0) {
++ x--;
++ *x = '0' + (v % 10);
++ v /= 10;
++ }
++ /* make up a name */
++ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
++ strcat(local_name, x);
++ strncpy(name, local_name, buffer_size - 1);
++ }
++}
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
++{
++ memset(name, 0, buffer_size * sizeof(YCHAR));
++ yaffs_check_obj_details_loaded(obj);
++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
++ } else if (obj->short_name[0]) {
++ strcpy(name, obj->short_name);
++ } else if (obj->hdr_chunk > 0) {
++ int result;
++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
++
++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
++
++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
++
++ if (obj->hdr_chunk > 0) {
++ result = yaffs_rd_chunk_tags_nand(obj->my_dev,
++ obj->hdr_chunk,
++ buffer, NULL);
++ }
++ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
++ buffer_size);
++
++ yaffs_release_temp_buffer(obj->my_dev, buffer);
++ }
++
++ yaffs_fix_null_name(obj, name, buffer_size);
++
++ return strnlen(name, YAFFS_MAX_NAME_LENGTH);
++}
++
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
++{
++ /* Dereference any hard linking */
++ obj = yaffs_get_equivalent_obj(obj);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ return obj->variant.file_variant.file_size;
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ if (!obj->variant.symlink_variant.alias)
++ return 0;
++ return strnlen(obj->variant.symlink_variant.alias,
++ YAFFS_MAX_ALIAS_LENGTH);
++ } else {
++ /* Only a directory should drop through to here */
++ return obj->my_dev->data_bytes_per_chunk;
++ }
++}
++
++int yaffs_get_obj_link_count(struct yaffs_obj *obj)
++{
++ int count = 0;
++ struct list_head *i;
++
++ if (!obj->unlinked)
++ count++; /* the object itself */
++
++ list_for_each(i, &obj->hard_links)
++ count++; /* add the hard links; */
++
++ return count;
++}
++
++int yaffs_get_obj_inode(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ return obj->obj_id;
++}
++
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return DT_DIR;
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return DT_LNK;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ if (S_ISFIFO(obj->yst_mode))
++ return DT_FIFO;
++ if (S_ISCHR(obj->yst_mode))
++ return DT_CHR;
++ if (S_ISBLK(obj->yst_mode))
++ return DT_BLK;
++ if (S_ISSOCK(obj->yst_mode))
++ return DT_SOCK;
++ return DT_REG;
++ break;
++ default:
++ return DT_REG;
++ break;
++ }
++}
++
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
++ return yaffs_clone_str(obj->variant.symlink_variant.alias);
++ else
++ return yaffs_clone_str(_Y(""));
++}
++
++/*--------------------------- Initialisation code -------------------------- */
++
++static int yaffs_check_dev_fns(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++ struct yaffs_tags_handler *tagger = &dev->tagger;
++
++ /* Common functions, gotta have */
++ if (!drv->drv_read_chunk_fn ||
++ !drv->drv_write_chunk_fn ||
++ !drv->drv_erase_fn)
++ return 0;
++
++ if (dev->param.is_yaffs2 &&
++ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
++ return 0;
++
++ /* Install the default tags marshalling functions if needed. */
++ yaffs_tags_compat_install(dev);
++ yaffs_tags_marshall_install(dev);
++
++ /* Check we now have the marshalling functions required. */
++ if (!tagger->write_chunk_tags_fn ||
++ !tagger->read_chunk_tags_fn ||
++ !tagger->query_block_fn ||
++ !tagger->mark_bad_fn)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs_create_initial_dir(struct yaffs_dev *dev)
++{
++ /* Initialise the unlinked, deleted, root and lost+found directories */
++ dev->lost_n_found = dev->root_dir = NULL;
++ dev->unlinked_dir = dev->del_dir = NULL;
++ dev->unlinked_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++ dev->del_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++ dev->root_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
++ YAFFS_ROOT_MODE | S_IFDIR);
++ dev->lost_n_found =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
++ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
++ && dev->del_dir) {
++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++/* Low level init.
++ * Typically only used by yaffs_guts_initialise, but also used by the
++ * Low level yaffs driver tests.
++ */
++
++int yaffs_guts_ll_init(struct yaffs_dev *dev)
++{
++
++
++ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
++
++ if (!dev) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Need a device"
++ );
++ return YAFFS_FAIL;
++ }
++
++ if (dev->ll_init)
++ return YAFFS_OK;
++
++ dev->internal_start_block = dev->param.start_block;
++ dev->internal_end_block = dev->param.end_block;
++ dev->block_offset = 0;
++ dev->chunk_offset = 0;
++ dev->n_free_chunks = 0;
++
++ dev->gc_block = 0;
++
++ if (dev->param.start_block == 0) {
++ dev->internal_start_block = dev->param.start_block + 1;
++ dev->internal_end_block = dev->param.end_block + 1;
++ dev->block_offset = 1;
++ dev->chunk_offset = dev->param.chunks_per_block;
++ }
++
++ /* Check geometry parameters. */
++
++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 1024) ||
++ (!dev->param.is_yaffs2 &&
++ dev->param.total_bytes_per_chunk < 512) ||
++ (dev->param.inband_tags && !dev->param.is_yaffs2) ||
++ dev->param.chunks_per_block < 2 ||
++ dev->param.n_reserved_blocks < 2 ||
++ dev->internal_start_block <= 0 ||
++ dev->internal_end_block <= 0 ||
++ dev->internal_end_block <=
++ (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
++ ) {
++ /* otherwise it is too small */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
++ dev->param.total_bytes_per_chunk,
++ dev->param.is_yaffs2 ? "2" : "",
++ dev->param.inband_tags);
++ return YAFFS_FAIL;
++ }
++
++ /* Sort out space for inband tags, if required */
++ if (dev->param.inband_tags)
++ dev->data_bytes_per_chunk =
++ dev->param.total_bytes_per_chunk -
++ sizeof(struct yaffs_packed_tags2_tags_only);
++ else
++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
++
++ /* Got the right mix of functions? */
++ if (!yaffs_check_dev_fns(dev)) {
++ /* Function missing */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "device function(s) missing or wrong");
++
++ return YAFFS_FAIL;
++ }
++
++ if (yaffs_init_nand(dev) != YAFFS_OK) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev)
++{
++ int i;
++ enum yaffs_block_state state;
++ u32 dummy;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if(dev->is_mounted)
++ return YAFFS_FAIL;
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ yaffs_query_init_block_state(dev, i, &state, &dummy);
++ if (state != YAFFS_BLOCK_STATE_DEAD)
++ yaffs_erase_block(dev, i);
++ }
++
++ return YAFFS_OK;
++}
++
++
++int yaffs_guts_initialise(struct yaffs_dev *dev)
++{
++ int init_failed = 0;
++ unsigned x;
++ int bits;
++
++ if(yaffs_guts_ll_init(dev) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ if (dev->is_mounted) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
++ return YAFFS_FAIL;
++ }
++
++ dev->is_mounted = 1;
++
++ /* OK now calculate a few things for the device */
++
++ /*
++ * Calculate all the chunk size manipulation numbers:
++ */
++ x = dev->data_bytes_per_chunk;
++ /* We always use dev->chunk_shift and dev->chunk_div */
++ dev->chunk_shift = calc_shifts(x);
++ x >>= dev->chunk_shift;
++ dev->chunk_div = x;
++ /* We only use chunk mask if chunk_div is 1 */
++ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
++
++ /*
++ * Calculate chunk_grp_bits.
++ * We need to find the next power of 2 > than internal_end_block
++ */
++
++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
++
++ bits = calc_shifts_ceiling(x);
++
++ /* Set up tnode width if wide tnodes are enabled. */
++ if (!dev->param.wide_tnodes_disabled) {
++ /* bits must be even so that we end up with 32-bit words */
++ if (bits & 1)
++ bits++;
++ if (bits < 16)
++ dev->tnode_width = 16;
++ else
++ dev->tnode_width = bits;
++ } else {
++ dev->tnode_width = 16;
++ }
++
++ dev->tnode_mask = (1 << dev->tnode_width) - 1;
++
++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++ * so if the bitwidth of the
++ * chunk range we're using is greater than 16 we need
++ * to figure out chunk shift and chunk_grp_size
++ */
++
++ if (bits <= dev->tnode_width)
++ dev->chunk_grp_bits = 0;
++ else
++ dev->chunk_grp_bits = bits - dev->tnode_width;
++
++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
++ if (dev->tnode_size < sizeof(struct yaffs_tnode))
++ dev->tnode_size = sizeof(struct yaffs_tnode);
++
++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
++
++ if (dev->param.chunks_per_block < dev->chunk_grp_size) {
++ /* We have a problem because the soft delete won't work if
++ * the chunk group size > chunks per block.
++ * This can be remedied by using larger "virtual blocks".
++ */
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
++
++ return YAFFS_FAIL;
++ }
++
++ /* Finished verifying the device, continue with initialisation */
++
++ /* More device initialisation */
++ dev->all_gcs = 0;
++ dev->passive_gc_count = 0;
++ dev->oldest_dirty_gc_count = 0;
++ dev->bg_gcs = 0;
++ dev->gc_block_finder = 0;
++ dev->buffered_block = -1;
++ dev->doing_buffered_block_rewrite = 0;
++ dev->n_deleted_files = 0;
++ dev->n_bg_deletions = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_ecc_fixed = 0;
++ dev->n_ecc_unfixed = 0;
++ dev->n_tags_ecc_fixed = 0;
++ dev->n_tags_ecc_unfixed = 0;
++ dev->n_erase_failures = 0;
++ dev->n_erased_blocks = 0;
++ dev->gc_disable = 0;
++ dev->has_pending_prioritised_gc = 1;
++ /* Assume the worst for now, will get fixed on first GC */
++ INIT_LIST_HEAD(&dev->dirty_dirs);
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++
++ /* Initialise temporary buffers and caches. */
++ if (!yaffs_init_tmp_buffers(dev))
++ init_failed = 1;
++
++ dev->cache = NULL;
++ dev->gc_cleanup_list = NULL;
++
++ if (!init_failed && dev->param.n_caches > 0) {
++ int i;
++ void *buf;
++ int cache_bytes =
++ dev->param.n_caches * sizeof(struct yaffs_cache);
++
++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
++
++ dev->cache = kmalloc(cache_bytes, GFP_NOFS);
++
++ buf = (u8 *) dev->cache;
++
++ if (dev->cache)
++ memset(dev->cache, 0, cache_bytes);
++
++ for (i = 0; i < dev->param.n_caches && buf; i++) {
++ dev->cache[i].object = NULL;
++ dev->cache[i].last_use = 0;
++ dev->cache[i].dirty = 0;
++ dev->cache[i].data = buf =
++ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++ }
++ if (!buf)
++ init_failed = 1;
++
++ dev->cache_last_use = 0;
++ }
++
++ dev->cache_hits = 0;
++
++ if (!init_failed) {
++ dev->gc_cleanup_list =
++ kmalloc(dev->param.chunks_per_block * sizeof(u32),
++ GFP_NOFS);
++ if (!dev->gc_cleanup_list)
++ init_failed = 1;
++ }
++
++ if (dev->param.is_yaffs2)
++ dev->param.use_header_file_size = 1;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && dev->param.is_yaffs2 &&
++ !dev->param.disable_summary &&
++ !yaffs_summary_init(dev))
++ init_failed = 1;
++
++ if (!init_failed) {
++ /* Now scan the flash. */
++ if (dev->param.is_yaffs2) {
++ if (yaffs2_checkpt_restore(dev)) {
++ yaffs_check_obj_details_loaded(dev->root_dir);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT |
++ YAFFS_TRACE_MOUNT,
++ "yaffs: restored from checkpoint"
++ );
++ } else {
++
++ /* Clean up the mess caused by an aborted
++ * checkpoint load then scan backwards.
++ */
++ yaffs_deinit_blocks(dev);
++
++ yaffs_deinit_tnodes_and_objs(dev);
++
++ dev->n_erased_blocks = 0;
++ dev->n_free_chunks = 0;
++ dev->alloc_block = -1;
++ dev->alloc_page = -1;
++ dev->n_deleted_files = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_bg_deletions = 0;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed
++ && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && !yaffs2_scan_backwards(dev))
++ init_failed = 1;
++ }
++ } else if (!yaffs1_scan(dev)) {
++ init_failed = 1;
++ }
++
++ yaffs_strip_deleted_objs(dev);
++ yaffs_fix_hanging_objs(dev);
++ if (dev->param.empty_lost_n_found)
++ yaffs_empty_l_n_f(dev);
++ }
++
++ if (init_failed) {
++ /* Clean up the mess */
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() aborted.");
++
++ yaffs_deinitialise(dev);
++ return YAFFS_FAIL;
++ }
++
++ /* Zero out stats */
++ dev->n_page_reads = 0;
++ dev->n_page_writes = 0;
++ dev->n_erasures = 0;
++ dev->n_gc_copies = 0;
++ dev->n_retried_writes = 0;
++
++ dev->n_retired_blocks = 0;
++
++ yaffs_verify_free_chunks(dev);
++ yaffs_verify_blocks(dev);
++
++ /* Clean up any aborted checkpoint data */
++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs_trace(YAFFS_TRACE_TRACING,
++ "yaffs: yaffs_guts_initialise() done.");
++ return YAFFS_OK;
++}
++
++void yaffs_deinitialise(struct yaffs_dev *dev)
++{
++ if (dev->is_mounted) {
++ int i;
++
++ yaffs_deinit_blocks(dev);
++ yaffs_deinit_tnodes_and_objs(dev);
++ yaffs_summary_deinit(dev);
++
++ if (dev->param.n_caches > 0 && dev->cache) {
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ kfree(dev->cache[i].data);
++ dev->cache[i].data = NULL;
++ }
++
++ kfree(dev->cache);
++ dev->cache = NULL;
++ }
++
++ kfree(dev->gc_cleanup_list);
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ kfree(dev->temp_buffer[i].buffer);
++
++ dev->is_mounted = 0;
++
++ yaffs_deinit_nand(dev);
++ }
++}
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev)
++{
++ int n_free = 0;
++ int b;
++ struct yaffs_block_info *blk;
++
++ blk = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++ switch (blk->block_state) {
++ case YAFFS_BLOCK_STATE_EMPTY:
++ case YAFFS_BLOCK_STATE_ALLOCATING:
++ case YAFFS_BLOCK_STATE_COLLECTING:
++ case YAFFS_BLOCK_STATE_FULL:
++ n_free +=
++ (dev->param.chunks_per_block - blk->pages_in_use +
++ blk->soft_del_pages);
++ break;
++ default:
++ break;
++ }
++ blk++;
++ }
++ return n_free;
++}
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
++{
++ /* This is what we report to the outside world */
++ int n_free;
++ int n_dirty_caches;
++ int blocks_for_checkpt;
++ int i;
++
++ n_free = dev->n_free_chunks;
++ n_free += dev->n_deleted_files;
++
++ /* Now count and subtract the number of dirty chunks in the cache. */
++
++ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].dirty)
++ n_dirty_caches++;
++ }
++
++ n_free -= n_dirty_caches;
++
++ n_free -=
++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
++
++ /* Now figure checkpoint space and report that... */
++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
++
++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
++
++ if (n_free < 0)
++ n_free = 0;
++
++ return n_free;
++}
++
++
++
++/*
++ * Marshalling functions to get loff_t file sizes into and out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
++{
++ oh->file_size_low = (fsize & 0xFFFFFFFF);
++ oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
++}
++
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
++{
++ loff_t retval;
++
++ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
++ retval = (((loff_t) oh->file_size_high) << 32) |
++ (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
++ else
++ retval = (loff_t) oh->file_size_low;
++
++ return retval;
++}
++
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
++{
++ int i;
++ struct yaffs_block_info *bi;
++ int s;
++
++ for(i = 0; i < 10; i++)
++ bs[i] = 0;
++
++ for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ bi = yaffs_get_block_info(dev, i);
++ s = bi->block_state;
++ if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
++ bs[0]++;
++ else
++ bs[s]++;
++ }
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_guts.h linux-3.4.90/fs/yaffs2/yaffs_guts.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_guts.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,1007 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "yportenv.h"
++
++#define YAFFS_OK 1
++#define YAFFS_FAIL 0
++
++/* Give us a Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xff
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC 0x5941ff53
++
++/*
++ * Tnodes form a tree with the tnodes in "levels"
++ * Levels greater than 0 hold 8 slots which point to other tnodes.
++ * Those at level 0 hold 16 slots which point to chunks in NAND.
++ *
++ * A maximum level of 8 thust supports files of size up to:
++ *
++ * 2^(3*MAX_LEVEL+4)
++ *
++ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
++ * a maximum file size of around 512Gbytees with 2k chunks.
++ */
++#define YAFFS_NTNODES_LEVEL0 16
++#define YAFFS_TNODES_LEVEL0_BITS 4
++#define YAFFS_TNODES_LEVEL0_MASK 0xf
++
++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK 0x7
++#define YAFFS_TNODES_MAX_LEVEL 8
++#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
++ YAFFS_TNODES_INTERNAL_BITS * \
++ YAFFS_TNODES_MAX_LEVEL)
++#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
++
++#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
++
++/* Constants for YAFFS1 mode */
++#define YAFFS_BYTES_PER_SPARE 16
++#define YAFFS_BYTES_PER_CHUNK 512
++#define YAFFS_CHUNK_SIZE_SHIFT 9
++#define YAFFS_CHUNKS_PER_BLOCK 32
++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
++
++
++
++#define YAFFS_ALLOCATION_NOBJECTS 100
++#define YAFFS_ALLOCATION_NTNODES 100
++#define YAFFS_ALLOCATION_NLINKS 100
++
++#define YAFFS_NOBJECT_BUCKETS 256
++
++#define YAFFS_OBJECT_SPACE 0x40000
++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
++
++/* Binary data version stamps */
++#define YAFFS_SUMMARY_VERSION 1
++#define YAFFS_CHECKPOINT_VERSION 7
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH 127
++#define YAFFS_MAX_ALIAS_LENGTH 79
++#else
++#define YAFFS_MAX_NAME_LENGTH 255
++#define YAFFS_MAX_ALIAS_LENGTH 159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH 15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT 1
++#define YAFFS_OBJECTID_LOSTNFOUND 2
++#define YAFFS_OBJECTID_UNLINKED 3
++#define YAFFS_OBJECTID_DELETED 4
++
++/* Fake object Id for summary data */
++#define YAFFS_OBJECTID_SUMMARY 0x10
++
++/* Pseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
++
++#define YAFFS_MAX_SHORT_OP_CACHES 20
++
++#define YAFFS_N_TEMP_BUFFERS 6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS (5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
++
++/* ChunkCache is used for short read/write operations.*/
++struct yaffs_cache {
++ struct yaffs_obj *object;
++ int chunk_id;
++ int last_use;
++ int dirty;
++ int n_bytes; /* Only valid if the cache is dirty */
++ int locked; /* Can't push out or flush while locked. */
++ u8 *data;
++};
++
++/* yaffs1 tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
++ * otherwise the structure size will get blown out.
++ */
++
++struct yaffs_tags {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes_lsb:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 n_bytes_msb:2;
++};
++
++union yaffs_tags_union {
++ struct yaffs_tags as_tags;
++ u8 as_bytes[8];
++};
++
++
++/* Stuff used for extended tags in YAFFS2 */
++
++enum yaffs_ecc_result {
++ YAFFS_ECC_RESULT_UNKNOWN,
++ YAFFS_ECC_RESULT_NO_ERROR,
++ YAFFS_ECC_RESULT_FIXED,
++ YAFFS_ECC_RESULT_UNFIXED
++};
++
++enum yaffs_obj_type {
++ YAFFS_OBJECT_TYPE_UNKNOWN,
++ YAFFS_OBJECT_TYPE_FILE,
++ YAFFS_OBJECT_TYPE_SYMLINK,
++ YAFFS_OBJECT_TYPE_DIRECTORY,
++ YAFFS_OBJECT_TYPE_HARDLINK,
++ YAFFS_OBJECT_TYPE_SPECIAL
++};
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++struct yaffs_ext_tags {
++ unsigned chunk_used; /* Status of the chunk: used or unused */
++ unsigned obj_id; /* If 0 this is not used */
++ unsigned chunk_id; /* If 0 this is a header, else a data chunk */
++ unsigned n_bytes; /* Only valid for data chunks */
++
++ /* The following stuff only has meaning when we read */
++ enum yaffs_ecc_result ecc_result;
++ unsigned block_bad;
++
++ /* YAFFS 1 stuff */
++ unsigned is_deleted; /* The chunk is marked deleted */
++ unsigned serial_number; /* Yaffs1 2-bit serial number */
++
++ /* YAFFS2 stuff */
++ unsigned seq_number; /* The sequence number of this block */
++
++ /* Extra info if this is an object header (YAFFS2 only) */
++
++ unsigned extra_available; /* Extra info available if not zero */
++ unsigned extra_parent_id; /* The parent object */
++ unsigned extra_is_shrink; /* Is it a shrink header? */
++ unsigned extra_shadows; /* Does this shadow another object? */
++
++ enum yaffs_obj_type extra_obj_type; /* What object type? */
++
++ loff_t extra_file_size; /* Length if it is a file */
++ unsigned extra_equiv_id; /* Equivalent object for a hard link */
++};
++
++/* Spare structure for YAFFS1 */
++struct yaffs_spare {
++ u8 tb0;
++ u8 tb1;
++ u8 tb2;
++ u8 tb3;
++ u8 page_status; /* set to 0 to delete the chunk */
++ u8 block_status;
++ u8 tb4;
++ u8 tb5;
++ u8 ecc1[3];
++ u8 tb6;
++ u8 tb7;
++ u8 ecc2[3];
++};
++
++/*Special structure for passing through to mtd */
++struct yaffs_nand_spare {
++ struct yaffs_spare spare;
++ int eccres1;
++ int eccres2;
++};
++
++/* Block data in RAM */
++
++enum yaffs_block_state {
++ YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++ YAFFS_BLOCK_STATE_SCANNING,
++ /* Being scanned */
++
++ YAFFS_BLOCK_STATE_NEEDS_SCAN,
++ /* The block might have something on it (ie it is allocating or full,
++ * perhaps empty) but it needs to be scanned to determine its true
++ * state.
++ * This state is only valid during scanning.
++ * NB We tolerate empty because the pre-scanner might be incapable of
++ * deciding
++ * However, if this state is returned on a YAFFS2 device,
++ * then we expect a sequence number
++ */
++
++ YAFFS_BLOCK_STATE_EMPTY,
++ /* This block is empty */
++
++ YAFFS_BLOCK_STATE_ALLOCATING,
++ /* This block is partially allocated.
++ * At least one page holds valid data.
++ * This is the one currently being used for page
++ * allocation. Should never be more than one of these.
++ * If a block is only partially allocated at mount it is treated as
++ * full.
++ */
++
++ YAFFS_BLOCK_STATE_FULL,
++ /* All the pages in this block have been allocated.
++ * If a block was only partially allocated when mounted we treat
++ * it as fully allocated.
++ */
++
++ YAFFS_BLOCK_STATE_DIRTY,
++ /* The block was full and now all chunks have been deleted.
++ * Erase me, reuse me.
++ */
++
++ YAFFS_BLOCK_STATE_CHECKPOINT,
++ /* This block is assigned to holding checkpoint data. */
++
++ YAFFS_BLOCK_STATE_COLLECTING,
++ /* This block is being garbage collected */
++
++ YAFFS_BLOCK_STATE_DEAD
++ /* This block has failed and is not in use */
++};
++
++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++struct yaffs_block_info {
++
++ s32 soft_del_pages:10; /* number of soft deleted pages */
++ s32 pages_in_use:10; /* number of pages in use */
++ u32 block_state:4; /* One of the above block states. */
++ /* NB use unsigned because enum is sometimes
++ * an int */
++ u32 needs_retiring:1; /* Data has failed on this block, */
++ /*need to get valid data off and retire*/
++ u32 skip_erased_check:1;/* Skip the erased check on this block */
++ u32 gc_prioritise:1; /* An ECC check or blank check has failed.
++ Block should be prioritised for GC */
++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc
++ failures on this block and tried to reuse it */
++ u32 has_summary:1; /* The block has a summary */
++
++ u32 has_shrink_hdr:1; /* This block has at least one shrink header */
++ u32 seq_number; /* block sequence number for yaffs2 */
++
++};
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++struct yaffs_obj_hdr {
++ enum yaffs_obj_type type;
++
++ /* Apply to everything */
++ int parent_obj_id;
++ u16 sum_no_longer_used; /* checksum of name. No longer used */
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ /* The following apply to all object types except for hard links */
++ u32 yst_mode; /* protection */
++
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++
++ /* File size applies to files only */
++ u32 file_size_low;
++
++ /* Equivalent object id applies to hard links only. */
++ int equiv_id;
++
++ /* Alias is for symlinks only. */
++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++ u32 yst_rdev; /* stuff for block and char devices (major/min) */
++
++ u32 win_ctime[2];
++ u32 win_atime[2];
++ u32 win_mtime[2];
++
++ u32 inband_shadowed_obj_id;
++ u32 inband_is_shrink;
++
++ u32 file_size_high;
++ u32 reserved[1];
++ int shadows_obj; /* This object header shadows the
++ specified object if > 0 */
++
++ /* is_shrink applies to object headers written when wemake a hole. */
++ u32 is_shrink;
++
++};
++
++/*--------------------------- Tnode -------------------------- */
++
++struct yaffs_tnode {
++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
++};
++
++/*------------------------ Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++struct yaffs_file_var {
++ loff_t file_size;
++ loff_t scanned_size;
++ loff_t shrink_size;
++ int top_level;
++ struct yaffs_tnode *top;
++};
++
++struct yaffs_dir_var {
++ struct list_head children; /* list of child links */
++ struct list_head dirty; /* Entry for list of dirty directories */
++};
++
++struct yaffs_symlink_var {
++ YCHAR *alias;
++};
++
++struct yaffs_hardlink_var {
++ struct yaffs_obj *equiv_obj;
++ u32 equiv_id;
++};
++
++union yaffs_obj_var {
++ struct yaffs_file_var file_variant;
++ struct yaffs_dir_var dir_variant;
++ struct yaffs_symlink_var symlink_variant;
++ struct yaffs_hardlink_var hardlink_variant;
++};
++
++struct yaffs_obj {
++ u8 deleted:1; /* This should only apply to unlinked files. */
++ u8 soft_del:1; /* it has also been soft deleted */
++ u8 unlinked:1; /* An unlinked file.*/
++ u8 fake:1; /* A fake object has no presence on NAND. */
++ u8 rename_allowed:1; /* Some objects cannot be renamed. */
++ u8 unlink_allowed:1;
++ u8 dirty:1; /* the object needs to be written to flash */
++ u8 valid:1; /* When the file system is being loaded up, this
++ * object might be created before the data
++ * is available
++ * ie. file data chunks encountered before
++ * the header.
++ */
++ u8 lazy_loaded:1; /* This object has been lazy loaded and
++ * is missing some detail */
++
++ u8 defered_free:1; /* Object is removed from NAND, but is
++ * still in the inode cache.
++ * Free of object is defered.
++ * until the inode is released.
++ */
++ u8 being_created:1; /* This object is still being created
++ * so skip some verification checks. */
++ u8 is_shadowed:1; /* This object is shadowed on the way
++ * to being renamed. */
++
++ u8 xattr_known:1; /* We know if this has object has xattribs
++ * or not. */
++ u8 has_xattr:1; /* This object has xattribs.
++ * Only valid if xattr_known. */
++
++ u8 serial; /* serial number of chunk in NAND.*/
++ u16 sum; /* sum of the name to speed searching */
++
++ struct yaffs_dev *my_dev; /* The device I'm on */
++
++ struct list_head hash_link; /* list of objects in hash bucket */
++
++ struct list_head hard_links; /* hard linked object chain*/
++
++ /* directory structure stuff */
++ /* also used for linking up the free list */
++ struct yaffs_obj *parent;
++ struct list_head siblings;
++
++ /* Where's my object header in NAND? */
++ int hdr_chunk;
++
++ int n_data_chunks; /* Number of data chunks for this file. */
++
++ u32 obj_id; /* the object id value */
++
++ u32 yst_mode;
++
++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
++
++#ifdef CONFIG_YAFFS_WINCE
++ u32 win_ctime[2];
++ u32 win_mtime[2];
++ u32 win_atime[2];
++#else
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++#endif
++
++ u32 yst_rdev;
++
++ void *my_inode;
++
++ enum yaffs_obj_type variant_type;
++
++ union yaffs_obj_var variant;
++
++};
++
++struct yaffs_obj_bucket {
++ struct list_head list;
++ int count;
++};
++
++/* yaffs_checkpt_obj holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++struct yaffs_checkpt_obj {
++ int struct_type;
++ u32 obj_id;
++ u32 parent_id;
++ int hdr_chunk;
++ enum yaffs_obj_type variant_type:3;
++ u8 deleted:1;
++ u8 soft_del:1;
++ u8 unlinked:1;
++ u8 fake:1;
++ u8 rename_allowed:1;
++ u8 unlink_allowed:1;
++ u8 serial;
++ int n_data_chunks;
++ loff_t size_or_equiv_obj;
++};
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few.
++ */
++
++struct yaffs_buffer {
++ u8 *buffer;
++ int in_use;
++};
++
++/*----------------- Device ---------------------------------*/
++
++struct yaffs_param {
++ const YCHAR *name;
++
++ /*
++ * Entry parameters set up way early. Yaffs sets up the rest.
++ * The structure should be zeroed out before use so that unused
++ * and default values are zero.
++ */
++
++ int inband_tags; /* Use unband tags */
++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
++ be a power of 2 */
++ int chunks_per_block; /* does not need to be a power of 2 */
++ int spare_bytes_per_chunk; /* spare area size */
++ int start_block; /* Start block we're allowed to use */
++ int end_block; /* End block we're allowed to use */
++ int n_reserved_blocks; /* Tuneable so that we can reduce
++ * reserved blocks on NOR and RAM. */
++
++ int n_caches; /* If <= 0, then short op caching is disabled,
++ * else the number of short op caches.
++ */
++ int cache_bypass_aligned; /* If non-zero then bypass the cache for
++ * aligned writes.
++ */
++
++ int use_nand_ecc; /* Flag to decide whether or not to use
++ * NAND driver ECC on data (yaffs1) */
++ int tags_9bytes; /* Use 9 byte tags */
++ int no_tags_ecc; /* Flag to decide whether or not to do ECC
++ * on packed tags (yaffs2) */
++
++ int is_yaffs2; /* Use yaffs2 mode on this device */
++
++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
++
++ int refresh_period; /* How often to check for a block refresh */
++
++ /* Checkpoint control. Can be set before or after initialisation */
++ u8 skip_checkpt_rd;
++ u8 skip_checkpt_wr;
++
++ int enable_xattr; /* Enable xattribs */
++
++ int max_objects; /*
++ * Set to limit the number of objects created.
++ * 0 = no limit.
++ */
++
++ /* The remove_obj_fn function must be supplied by OS flavours that
++ * need it.
++ * yaffs direct uses it to implement the faster readdir.
++ * Linux uses it to protect the directory during unlocking.
++ */
++ void (*remove_obj_fn) (struct yaffs_obj *obj);
++
++ /* Callback to mark the superblock dirty */
++ void (*sb_dirty_fn) (struct yaffs_dev *dev);
++
++ /* Callback to control garbage collection. */
++ unsigned (*gc_control_fn) (struct yaffs_dev *dev);
++
++ /* Debug control flags. Don't use unless you know what you're doing */
++ int use_header_file_size; /* Flag to determine if we should use
++ * file sizes from the header */
++ int disable_lazy_load; /* Disable lazy loading on this device */
++ int wide_tnodes_disabled; /* Set to disable wide tnodes */
++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of
++ * softdeletion. */
++
++ int defered_dir_update; /* Set to defer directory updates */
++
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ int auto_unicode;
++#endif
++ int always_check_erased; /* Force chunk erased check always on */
++
++ int disable_summary;
++ int disable_bad_block_marking;
++
++};
++
++struct yaffs_driver {
++ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len);
++ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result);
++ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
++ int (*drv_initialise_fn) (struct yaffs_dev *dev);
++ int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
++};
++
++struct yaffs_tags_handler {
++ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags);
++ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags);
++
++ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
++};
++
++struct yaffs_dev {
++ struct yaffs_param param;
++ struct yaffs_driver drv;
++ struct yaffs_tags_handler tagger;
++
++ /* Context storage. Holds extra OS specific data for this device */
++
++ void *os_context;
++ void *driver_context;
++
++ struct list_head dev_list;
++
++ int ll_init;
++ /* Runtime parameters. Set up by YAFFS. */
++ int data_bytes_per_chunk;
++
++ /* Non-wide tnode stuff */
++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
++ * the tnodes are not wide enough.
++ */
++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
++
++ /* Stuff to support wide tnodes */
++ u32 tnode_width;
++ u32 tnode_mask;
++ u32 tnode_size;
++
++ /* Stuff for figuring out file offset to chunk conversions */
++ u32 chunk_shift; /* Shift value */
++ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
++ u32 chunk_mask; /* Mask to use for power-of-2 case */
++
++ int is_mounted;
++ int read_only;
++ int is_checkpointed;
++
++ /* Stuff to support block offsetting to support start block zero */
++ int internal_start_block;
++ int internal_end_block;
++ int block_offset;
++ int chunk_offset;
++
++ /* Runtime checkpointing stuff */
++ int checkpt_page_seq; /* running sequence number of checkpt pages */
++ int checkpt_byte_count;
++ int checkpt_byte_offs;
++ u8 *checkpt_buffer;
++ int checkpt_open_write;
++ int blocks_in_checkpt;
++ int checkpt_cur_chunk;
++ int checkpt_cur_block;
++ int checkpt_next_block;
++ int *checkpt_block_list;
++ int checkpt_max_blocks;
++ u32 checkpt_sum;
++ u32 checkpt_xor;
++
++ int checkpoint_blocks_required; /* Number of blocks needed to store
++ * current checkpoint set */
++
++ /* Block Info */
++ struct yaffs_block_info *block_info;
++ u8 *chunk_bits; /* bitmap of chunks in use */
++ u8 block_info_alt:1; /* allocated using alternative alloc */
++ u8 chunk_bits_alt:1; /* allocated using alternative alloc */
++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
++ * Must be consistent with chunks_per_block.
++ */
++
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int alloc_block_finder; /* Used to search for next allocation block */
++
++ /* Object and Tnode memory management */
++ void *allocator;
++ int n_obj;
++ int n_tnodes;
++
++ int n_hardlinks;
++
++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
++ u32 bucket_finder;
++
++ int n_free_chunks;
++
++ /* Garbage collection control */
++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
++ u32 n_clean_ups;
++
++ unsigned has_pending_prioritised_gc; /* We think this device might
++ have pending prioritised gcs */
++ unsigned gc_disable;
++ unsigned gc_block_finder;
++ unsigned gc_dirtiest;
++ unsigned gc_pages_in_use;
++ unsigned gc_not_done;
++ unsigned gc_block;
++ unsigned gc_chunk;
++ unsigned gc_skip;
++ struct yaffs_summary_tags *gc_sum_tags;
++
++ /* Special directories */
++ struct yaffs_obj *root_dir;
++ struct yaffs_obj *lost_n_found;
++
++ int buffered_block; /* Which block is buffered here? */
++ int doing_buffered_block_rewrite;
++
++ struct yaffs_cache *cache;
++ int cache_last_use;
++
++ /* Stuff for background deletion and unlinked files. */
++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
++ files live. */
++ struct yaffs_obj *del_dir; /* Directory where deleted objects are
++ sent to disappear. */
++ struct yaffs_obj *unlinked_deletion; /* Current file being
++ background deleted. */
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* Temporary buffer management */
++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
++ int max_temp;
++ int temp_in_use;
++ int unmanaged_buffer_allocs;
++ int unmanaged_buffer_deallocs;
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ allocating block */
++ unsigned oldest_dirty_seq;
++ unsigned oldest_dirty_block;
++
++ /* Block refreshing */
++ int refresh_skip; /* A skip down counter.
++ * Refresh happens when this gets to zero. */
++
++ /* Dirty directory handling */
++ struct list_head dirty_dirs; /* List of dirty directories */
++
++ /* Summary */
++ int chunks_per_summary;
++ struct yaffs_summary_tags *sum_tags;
++
++ /* Statistics */
++ u32 n_page_writes;
++ u32 n_page_reads;
++ u32 n_erasures;
++ u32 n_bad_queries;
++ u32 n_bad_markings;
++ u32 n_erase_failures;
++ u32 n_gc_copies;
++ u32 all_gcs;
++ u32 passive_gc_count;
++ u32 oldest_dirty_gc_count;
++ u32 n_gc_blocks;
++ u32 bg_gcs;
++ u32 n_retried_writes;
++ u32 n_retired_blocks;
++ u32 n_ecc_fixed;
++ u32 n_ecc_unfixed;
++ u32 n_tags_ecc_fixed;
++ u32 n_tags_ecc_unfixed;
++ u32 n_deletions;
++ u32 n_unmarked_deletions;
++ u32 refresh_count;
++ u32 cache_hits;
++ u32 tags_used;
++ u32 summary_used;
++
++};
++
++/* The CheckpointDevice structure holds the device information that changes
++ *at runtime and must be preserved over unmount/mount cycles.
++ */
++struct yaffs_checkpt_dev {
++ int struct_type;
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int n_free_chunks;
++
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently
++ * allocating block */
++
++};
++
++struct yaffs_checkpt_validity {
++ int struct_type;
++ u32 magic;
++ u32 version;
++ u32 head;
++};
++
++struct yaffs_shadow_fixer {
++ int obj_id;
++ int shadowed_id;
++ struct yaffs_shadow_fixer *next;
++};
++
++/* Structure for doing xattr modifications */
++struct yaffs_xattr_mod {
++ int set; /* If 0 then this is a deletion */
++ const YCHAR *name;
++ const void *data;
++ int size;
++ int flags;
++ int result;
++};
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_guts_initialise(struct yaffs_dev *dev);
++void yaffs_deinitialise(struct yaffs_dev *dev);
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++ struct yaffs_obj *new_dir, const YCHAR * new_name);
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
++int yaffs_del_obj(struct yaffs_obj *obj);
++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
++ enum yaffs_obj_type type);
++
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
++loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
++int yaffs_get_obj_inode(struct yaffs_obj *obj);
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
++int yaffs_get_obj_link_count(struct yaffs_obj *obj);
++
++/* File operations */
++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
++ int n_bytes);
++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid);
++
++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
++
++/* Flushing and checkpointing */
++void yaffs_flush_whole_cache(struct yaffs_dev *dev);
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev);
++int yaffs_checkpoint_restore(struct yaffs_dev *dev);
++
++/* Directory operations */
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
++ u32 mode, u32 uid, u32 gid);
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
++ const YCHAR *name);
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
++
++/* Link operations */
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
++ struct yaffs_obj *equiv_obj);
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
++
++/* Symlink operations */
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, const YCHAR *alias);
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR *name, u32 mode, u32 uid,
++ u32 gid, u32 rdev);
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
++ const void *value, int size, int flags);
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
++ int size);
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
++
++/* Special directories */
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj);
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
++
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
++
++/* Debug dump */
++int yaffs_dump_obj(struct yaffs_obj *obj);
++
++void yaffs_guts_test(struct yaffs_dev *dev);
++int yaffs_guts_ll_init(struct yaffs_dev *dev);
++
++
++/* A few useful functions to be used within the core files*/
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn);
++int yaffs_check_ff(u8 *buffer, int n_bytes);
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type);
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan);
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh);
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
++YCHAR *yaffs_clone_str(const YCHAR *str);
++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
++ int force, int is_shrink, int shadows,
++ struct yaffs_xattr_mod *xop);
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning);
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn);
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id);
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos);
++
++int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
++
++int yaffs_guts_format_dev(struct yaffs_dev *dev);
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 *offset_out);
++/*
++ * Marshalling functions to get loff_t file sizes into aand out of
++ * object headers.
++ */
++void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
++loff_t yaffs_max_file_size(struct yaffs_dev *dev);
++
++/*
++ * Debug function to count number of blocks in each state
++ * NB Needs to be called with correct number of integers
++ */
++
++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
++
++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_linux.h linux-3.4.90/fs/yaffs2/yaffs_linux.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_linux.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_LINUX_H__
++#define __YAFFS_LINUX_H__
++
++#include "yportenv.h"
++
++struct yaffs_linux_context {
++ struct list_head context_list; /* List of these we have mounted */
++ struct yaffs_dev *dev;
++ struct super_block *super;
++ struct task_struct *bg_thread; /* Background thread for this device */
++ int bg_running;
++ struct mutex gross_lock; /* Gross locking mutex*/
++ u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
++ * at compile time so we have to allocate it.
++ */
++ struct list_head search_contexts;
++ struct task_struct *readdir_process;
++ unsigned mount_id;
++ int dirty;
++};
++
++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
++
++#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
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.c linux-3.4.90/fs/yaffs2/yaffs_mtdif.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_mtdif.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,309 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/major.h"
++#include "linux/mtd/nand.h"
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_linux.h"
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++#define mtd_erase(m, ei) (m)->erase(m, ei)
++#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
++#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
++#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
++#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
++#endif
++
++
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ u32 addr =
++ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ struct erase_info ei;
++ int retval = 0;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++
++static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
++ const u8 *data, int data_len,
++ const u8 *oob, int oob_len)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
++ dev, nand_chunk, data, data_len, oob, oob_len);
++
++ if (!data || !data_len) {
++ data = NULL;
++ data_len = 0;
++ }
++
++ if (!oob || !oob_len) {
++ oob = NULL;
++ oob_len = 0;
++ }
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = (u8 *)data;
++ ops.oobbuf = (u8 *)oob;
++
++ retval = mtd_write_oob(mtd, addr, &ops);
++ if (retval) {
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "write_oob failed, chunk %d, mtd error %d",
++ nand_chunk, retval);
++ }
++ return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
++ u8 *data, int data_len,
++ u8 *oob, int oob_len,
++ enum yaffs_ecc_result *ecc_result)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ loff_t addr;
++ struct mtd_oob_ops ops;
++ int retval;
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OPS_AUTO_OOB;
++ ops.len = (data) ? data_len : 0;
++ ops.ooblen = oob_len;
++ ops.datbuf = data;
++ ops.oobbuf = oob;
++
++#if (MTD_VERSION_CODE < MTD_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",
++ nand_chunk, retval);
++
++ switch (retval) {
++ case 0:
++ /* no error */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++
++ case -EUCLEAN:
++ /* MTD's ECC fixed the data */
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ break;
++
++ case -EBADMSG:
++ default:
++ /* MTD's ECC could not fix the data */
++ dev->n_ecc_unfixed++;
++ if(ecc_result)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ return YAFFS_FAIL;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ loff_t addr;
++ struct erase_info ei;
++ int retval = 0;
++ u32 block_size;
++
++ block_size = dev->param.total_bytes_per_chunk *
++ dev->param.chunks_per_block;
++ addr = ((loff_t) block_no) * block_size;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = block_size;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd_erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++
++ return YAFFS_FAIL;
++}
++
++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
++
++ retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
++
++ retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++static int yaffs_mtd_initialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
++
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev)
++{
++ struct yaffs_driver *drv = &dev->drv;
++
++ drv->drv_write_chunk_fn = yaffs_mtd_write;
++ drv->drv_read_chunk_fn = yaffs_mtd_read;
++ drv->drv_erase_fn = yaffs_mtd_erase;
++ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
++ drv->drv_check_bad_fn = yaffs_mtd_check_bad;
++ drv->drv_initialise_fn = yaffs_mtd_initialise;
++ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
++}
++
++
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
++{
++ struct mtd_info *mtd;
++
++ mtd = yaffs_get_mtd_device(sdev);
++
++ /* Check it's an mtd device..... */
++ if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
++ return NULL; /* This isn't an mtd device */
++
++ /* Check it's NAND */
++ if (mtd->type != MTD_NANDFLASH) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device is not NAND it's type %d",
++ mtd->type);
++ return NULL;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
++ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
++ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++ yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
++#else
++ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
++#endif
++
++ return mtd;
++}
++
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++{
++ if (yaffs_version == 2) {
++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++ !inband_tags) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not have the right page sizes"
++ );
++ return -1;
++ }
++ } else {
++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "MTD device does not support have the right page sizes"
++ );
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++
++void yaffs_put_mtd_device(struct mtd_info *mtd)
++{
++ if(mtd)
++ put_mtd_device(mtd);
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.h linux-3.4.90/fs/yaffs2/yaffs_mtdif.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_mtdif.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_mtd_drv_install(struct yaffs_dev *dev);
++struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
++void yaffs_put_mtd_device(struct mtd_info *mtd);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.c linux-3.4.90/fs/yaffs2/yaffs_nameval.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_nameval.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This simple implementation of a name-value store assumes a small number of
++* values and fits into a small finite buffer.
++ *
++ * Each attribute is stored as a record:
++ * sizeof(int) bytes record size.
++ * strnlen+1 bytes name null terminated.
++ * nbytes value.
++ * ----------
++ * total size stored in record size
++ *
++ * This code has not been tested with unicode yet.
++ */
++
++#include "yaffs_nameval.h"
++
++#include "yportenv.h"
++
++static int nval_find(const char *xb, int xb_size, const YCHAR *name,
++ int *exist_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
++ name, size)) {
++ if (exist_size)
++ *exist_size = size;
++ return pos;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ if (exist_size)
++ *exist_size = 0;
++ return -ENODATA;
++}
++
++static int nval_used(const char *xb, int xb_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return pos;
++}
++
++int nval_del(char *xb, int xb_size, const YCHAR *name)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos < 0 || pos >= xb_size)
++ return -ENODATA;
++
++ /* Find size, shift rest over this record,
++ * then zero out the rest of buffer */
++ memcpy(&size, xb + pos, sizeof(int));
++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
++ memset(xb + (xb_size - size), 0, size);
++ return 0;
++}
++
++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
++ int bsize, int flags)
++{
++ int pos;
++ int namelen = strnlen(name, xb_size);
++ int reclen;
++ int size_exist = 0;
++ int space;
++ int start;
++
++ pos = nval_find(xb, xb_size, name, &size_exist);
++
++ if (flags & XATTR_CREATE && pos >= 0)
++ return -EEXIST;
++ if (flags & XATTR_REPLACE && pos < 0)
++ return -ENODATA;
++
++ start = nval_used(xb, xb_size);
++ space = xb_size - start + size_exist;
++
++ reclen = (sizeof(int) + namelen + 1 + bsize);
++
++ if (reclen > space)
++ return -ENOSPC;
++
++ if (pos >= 0) {
++ nval_del(xb, xb_size, name);
++ start = nval_used(xb, xb_size);
++ }
++
++ pos = start;
++
++ memcpy(xb + pos, &reclen, sizeof(int));
++ pos += sizeof(int);
++ strncpy((YCHAR *) (xb + pos), name, reclen);
++ pos += (namelen + 1);
++ memcpy(xb + pos, buf, bsize);
++ return 0;
++}
++
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos >= 0 && pos < xb_size) {
++
++ memcpy(&size, xb + pos, sizeof(int));
++ pos += sizeof(int); /* advance past record length */
++ size -= sizeof(int);
++
++ /* Advance over name string */
++ while (xb[pos] && size > 0 && pos < xb_size) {
++ pos++;
++ size--;
++ }
++ /*Advance over NUL */
++ pos++;
++ size--;
++
++ /* If bsize is zero then this is a size query.
++ * Return the size, but don't copy.
++ */
++ if (!bsize)
++ return size;
++
++ if (size <= bsize) {
++ memcpy(buf, xb + pos, size);
++ return size;
++ }
++ }
++ if (pos >= 0)
++ return -ERANGE;
++
++ return -ENODATA;
++}
++
++int nval_list(const char *xb, int xb_size, char *buf, int bsize)
++{
++ int pos = 0;
++ int size;
++ int name_len;
++ int ncopied = 0;
++ int filled = 0;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > sizeof(int) &&
++ size <= xb_size &&
++ (pos + size) < xb_size &&
++ !filled) {
++ pos += sizeof(int);
++ size -= sizeof(int);
++ name_len = strnlen((YCHAR *) (xb + pos), size);
++ if (ncopied + name_len + 1 < bsize) {
++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
++ buf += name_len;
++ *buf = '\0';
++ buf++;
++ if (sizeof(YCHAR) > 1) {
++ *buf = '\0';
++ buf++;
++ }
++ ncopied += (name_len + 1);
++ } else {
++ filled = 1;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return ncopied;
++}
++
++int nval_hasvalues(const char *xb, int xb_size)
++{
++ return nval_used(xb, xb_size) > 0;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.h linux-3.4.90/fs/yaffs2/yaffs_nameval.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_nameval.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __NAMEVAL_H__
++#define __NAMEVAL_H__
++
++#include "yportenv.h"
++
++int nval_del(char *xb, int xb_size, const YCHAR * name);
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++ int bsize, int flags);
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize);
++int nval_list(const char *xb, int xb_size, char *buf, int bsize);
++int nval_hasvalues(const char *xb, int xb_size);
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nand.c linux-3.4.90/fs/yaffs2/yaffs_nand.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_nand.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,122 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++
++#include "yaffs_getblockinfo.h"
++#include "yaffs_summary.h"
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++ return chunk - dev->chunk_offset;
++}
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ struct yaffs_ext_tags local_tags;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_reads++;
++
++ /* If there are no tags provided use local tags. */
++ if (!tags)
++ tags = &local_tags;
++
++ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
++
++ struct yaffs_block_info *bi;
++ bi = yaffs_get_block_info(dev,
++ nand_chunk /
++ dev->param.chunks_per_block);
++ yaffs_handle_chunk_error(dev, bi);
++ }
++ return result;
++}
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
++
++ dev->n_page_writes++;
++
++ if (!tags) {
++ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
++ BUG();
++ return YAFFS_FAIL;
++ }
++
++ tags->seq_number = dev->seq_number;
++ tags->chunk_used = 1;
++ yaffs_trace(YAFFS_TRACE_WRITE,
++ "Writing chunk %d tags %d %d",
++ nand_chunk, tags->obj_id, tags->chunk_id);
++
++ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
++ buffer, tags);
++
++ yaffs_summary_add(dev, tags, nand_chunk);
++
++ return result;
++}
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ block_no -= dev->block_offset;
++ dev->n_bad_markings++;
++
++ if (dev->param.disable_bad_block_marking)
++ return YAFFS_OK;
++
++ return dev->tagger.mark_bad_fn(dev, block_no);
++}
++
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ block_no -= dev->block_offset;
++ return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
++}
++
++int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ int result;
++
++ block_no -= dev->block_offset;
++ dev->n_erasures++;
++ result = dev->drv.drv_erase_fn(dev, block_no);
++ return result;
++}
++
++int yaffs_init_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_initialise_fn)
++ return dev->drv.drv_initialise_fn(dev);
++ return YAFFS_OK;
++}
++
++int yaffs_deinit_nand(struct yaffs_dev *dev)
++{
++ if (dev->drv.drv_deinitialise_fn)
++ return dev->drv.drv_deinitialise_fn(dev);
++ return YAFFS_OK;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_nand.h linux-3.4.90/fs/yaffs2/yaffs_nand.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_nand.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ unsigned *seq_number);
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
++
++int yaffs_init_nand(struct yaffs_dev *dev);
++int yaffs_deinit_nand(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.4.90/fs/yaffs2/yaffs_packedtags1.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_packedtags1.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++static const u8 all_ff[20] = {
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff,
++ 0xff, 0xff, 0xff, 0xff
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t)
++{
++ pt->chunk_id = t->chunk_id;
++ pt->serial_number = t->serial_number;
++ pt->n_bytes = t->n_bytes;
++ pt->obj_id = t->obj_id;
++ pt->ecc = 0;
++ pt->deleted = (t->is_deleted) ? 0 : 1;
++ pt->unused_stuff = 0;
++ pt->should_be_ff = 0xffffffff;
++}
++
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt)
++{
++
++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
++ t->block_bad = 0;
++ if (pt->should_be_ff != 0xffffffff)
++ t->block_bad = 1;
++ t->chunk_used = 1;
++ t->obj_id = pt->obj_id;
++ t->chunk_id = pt->chunk_id;
++ t->n_bytes = pt->n_bytes;
++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ t->is_deleted = (pt->deleted) ? 0 : 1;
++ t->serial_number = pt->serial_number;
++ } else {
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++ }
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.4.90/fs/yaffs2/yaffs_packedtags1.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_packedtags1.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++struct yaffs_packed_tags1 {
++ u32 chunk_id:20;
++ u32 serial_number:2;
++ u32 n_bytes:10;
++ u32 obj_id:18;
++ u32 ecc:12;
++ u32 deleted:1;
++ u32 unused_stuff:1;
++ unsigned should_be_ff;
++
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt);
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.4.90/fs/yaffs2/yaffs_packedtags2.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_packedtags2.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunk_id */
++
++#define EXTRA_HEADER_INFO_FLAG 0x80000000
++#define EXTRA_SHRINK_FLAG 0x40000000
++#define EXTRA_SHADOWS_FLAG 0x20000000
++#define EXTRA_SPARE_FLAGS 0x10000000
++
++#define ALL_EXTRA_FLAGS 0xf0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
++
++static void yaffs_dump_packed_tags2_tags_only(
++ const struct yaffs_packed_tags2_tags_only *ptt)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "packed tags obj %d chunk %d byte %d seq %d",
++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
++}
++
++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
++{
++ yaffs_dump_packed_tags2_tags_only(&pt->t);
++}
++
++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
++{
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
++ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
++ t->seq_number);
++
++}
++
++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
++{
++ if (t->chunk_id != 0 || !t->extra_available)
++ return 0;
++
++ /* Check if the file size is too long to store */
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
++ (t->extra_file_size >> 31) != 0)
++ return 0;
++ return 1;
++}
++
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
++ const struct yaffs_ext_tags *t)
++{
++ ptt->chunk_id = t->chunk_id;
++ ptt->seq_number = t->seq_number;
++ ptt->n_bytes = t->n_bytes;
++ ptt->obj_id = t->obj_id;
++
++ /* Only store extra tags for object headers.
++ * If it is a file then only store if the file size is short\
++ * enough to fit.
++ */
++ if (yaffs_check_tags_extra_packable(t)) {
++ /* Store the extra header info instead */
++ /* We save the parent object in the chunk_id */
++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
++ if (t->extra_is_shrink)
++ ptt->chunk_id |= EXTRA_SHRINK_FLAG;
++ if (t->extra_shadows)
++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
++
++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ ptt->n_bytes = t->extra_equiv_id;
++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ ptt->n_bytes = (unsigned) t->extra_file_size;
++ else
++ ptt->n_bytes = 0;
++ }
++
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc)
++{
++ yaffs_pack_tags2_tags_only(&pt->t, t);
++
++ if (tags_ecc)
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc);
++}
++
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *ptt)
++{
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++
++ if (ptt->seq_number == 0xffffffff)
++ return;
++
++ t->block_bad = 0;
++ t->chunk_used = 1;
++ t->obj_id = ptt->obj_id;
++ t->chunk_id = ptt->chunk_id;
++ t->n_bytes = ptt->n_bytes;
++ t->is_deleted = 0;
++ t->serial_number = 0;
++ t->seq_number = ptt->seq_number;
++
++ /* Do extra header info stuff */
++ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
++ t->chunk_id = 0;
++ t->n_bytes = 0;
++
++ t->extra_available = 1;
++ t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
++ t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
++ t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
++ t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ t->extra_equiv_id = ptt->n_bytes;
++ else
++ t->extra_file_size = ptt->n_bytes;
++ }
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc)
++{
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ if (pt->t.seq_number != 0xffffffff && tags_ecc) {
++ /* Chunk is in use and we need to do ECC */
++
++ struct yaffs_ecc_other ecc;
++ int result;
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &ecc);
++ result =
++ yaffs_ecc_correct_other((unsigned char *)&pt->t,
++ sizeof(struct yaffs_packed_tags2_tags_only),
++ &pt->ecc, &ecc);
++ switch (result) {
++ case 0:
++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++ case 1:
++ ecc_result = YAFFS_ECC_RESULT_FIXED;
++ break;
++ case -1:
++ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ break;
++ default:
++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ }
++ }
++ yaffs_unpack_tags2_tags_only(t, &pt->t);
++
++ t->ecc_result = ecc_result;
++
++ yaffs_dump_packed_tags2(pt);
++ yaffs_dump_tags2(t);
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.4.90/fs/yaffs2/yaffs_packedtags2.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_packedtags2.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++struct yaffs_packed_tags2_tags_only {
++ unsigned seq_number;
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++struct yaffs_packed_tags2 {
++ struct yaffs_packed_tags2_tags_only t;
++ struct yaffs_ecc_other ecc;
++};
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc);
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *pt);
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_summary.c linux-3.4.90/fs/yaffs2/yaffs_summary.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_summary.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_summary.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,312 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* Summaries write the useful part of the tags for the chunks in a block into an
++ * an array which is written to the last n chunks of the block.
++ * Reading the summaries gives all the tags for the block in one read. Much
++ * faster.
++ *
++ * Chunks holding summaries are marked with tags making it look like
++ * they are part of a fake file.
++ *
++ * The summary could also be used during gc.
++ *
++ */
++
++#include "yaffs_summary.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_bitmap.h"
++
++/*
++ * The summary is built up in an array of summary tags.
++ * This gets written to the last one or two (maybe more) chunks in a block.
++ * A summary header is written as the first part of each chunk of summary data.
++ * The summary header must match or the summary is rejected.
++ */
++
++/* Summary tags don't need the sequence number because that is redundant. */
++struct yaffs_summary_tags {
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++/* Summary header */
++struct yaffs_summary_header {
++ unsigned version; /* Must match current version */
++ unsigned block; /* Must be this block */
++ unsigned seq; /* Must be this sequence number */
++ unsigned sum; /* Just add up all the bytes in the tags */
++};
++
++
++static void yaffs_summary_clear(struct yaffs_dev *dev)
++{
++ if (!dev->sum_tags)
++ return;
++ memset(dev->sum_tags, 0, dev->chunks_per_summary *
++ sizeof(struct yaffs_summary_tags));
++}
++
++
++void yaffs_summary_deinit(struct yaffs_dev *dev)
++{
++ kfree(dev->sum_tags);
++ dev->sum_tags = NULL;
++ kfree(dev->gc_sum_tags);
++ dev->gc_sum_tags = NULL;
++ dev->chunks_per_summary = 0;
++}
++
++int yaffs_summary_init(struct yaffs_dev *dev)
++{
++ int sum_bytes;
++ int chunks_used; /* Number of chunks used by summary */
++ int sum_tags_bytes;
++
++ sum_bytes = dev->param.chunks_per_block *
++ sizeof(struct yaffs_summary_tags);
++
++ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
++ (dev->data_bytes_per_chunk -
++ sizeof(struct yaffs_summary_header));
++
++ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
++ if (!dev->sum_tags || !dev->gc_sum_tags) {
++ yaffs_summary_deinit(dev);
++ return YAFFS_FAIL;
++ }
++
++ yaffs_summary_clear(dev);
++
++ return YAFFS_OK;
++}
++
++static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
++{
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int i;
++ unsigned sum = 0;
++
++ i = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ while (i > 0) {
++ sum += *sum_buffer;
++ sum_buffer++;
++ i--;
++ }
++
++ return sum;
++}
++
++static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)dev->sum_tags;
++ int n_bytes;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ memset(&tags, 0, sizeof(struct yaffs_ext_tags));
++ tags.obj_id = YAFFS_OBJECTID_SUMMARY;
++ tags.chunk_id = 1;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ hdr.version = YAFFS_SUMMARY_VERSION;
++ hdr.block = blk;
++ hdr.seq = bi->seq_number;
++ hdr.sum = yaffs_summary_sum(dev);
++
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ memcpy(buffer, &hdr, sizeof(hdr));
++ memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
++ tags.n_bytes = this_tx + sizeof(hdr);
++ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (result != YAFFS_OK)
++ break;
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ dev->n_free_chunks--;
++
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ tags.chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++
++ if (result == YAFFS_OK)
++ bi->has_summary = 1;
++
++
++ return result;
++}
++
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk)
++{
++ struct yaffs_ext_tags tags;
++ u8 *buffer;
++ u8 *sum_buffer = (u8 *)st;
++ int n_bytes;
++ int chunk_id;
++ int chunk_in_nand;
++ int chunk_in_block;
++ int result;
++ int this_tx;
++ struct yaffs_summary_header hdr;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
++ int sum_tags_bytes;
++
++ sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
++ dev->chunks_per_summary;
++ buffer = yaffs_get_temp_buffer(dev);
++ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
++ chunk_in_block = dev->chunks_per_summary;
++ chunk_in_nand = blk * dev->param.chunks_per_block +
++ dev->chunks_per_summary;
++ chunk_id = 1;
++ do {
++ this_tx = n_bytes;
++ if (this_tx > sum_bytes_per_chunk)
++ this_tx = sum_bytes_per_chunk;
++ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
++ buffer, &tags);
++
++ if (tags.chunk_id != chunk_id ||
++ tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
++ tags.chunk_used == 0 ||
++ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++ tags.n_bytes != (this_tx + sizeof(hdr)))
++ result = YAFFS_FAIL;
++ if (result != YAFFS_OK)
++ break;
++
++ if (st == dev->sum_tags) {
++ /* If we're scanning then update the block info */
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++ }
++ memcpy(&hdr, buffer, sizeof(hdr));
++ memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
++ n_bytes -= this_tx;
++ sum_buffer += this_tx;
++ chunk_in_nand++;
++ chunk_in_block++;
++ chunk_id++;
++ } while (result == YAFFS_OK && n_bytes > 0);
++ yaffs_release_temp_buffer(dev, buffer);
++
++ if (result == YAFFS_OK) {
++ /* Verify header */
++ if (hdr.version != YAFFS_SUMMARY_VERSION ||
++ hdr.seq != bi->seq_number ||
++ hdr.sum != yaffs_summary_sum(dev))
++ result = YAFFS_FAIL;
++ }
++
++ if (st == dev->sum_tags && result == YAFFS_OK)
++ bi->has_summary = 1;
++
++ return result;
++}
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_nand)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
++ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
++
++ if (!dev->sum_tags)
++ return YAFFS_OK;
++
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ yaffs_pack_tags2_tags_only(&tags_only, tags);
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ sum_tags->chunk_id = tags_only.chunk_id;
++ sum_tags->n_bytes = tags_only.n_bytes;
++ sum_tags->obj_id = tags_only.obj_id;
++
++ if (chunk_in_block == dev->chunks_per_summary - 1) {
++ /* Time to write out the summary */
++ yaffs_summary_write(dev, block_in_nand);
++ yaffs_summary_clear(dev);
++ yaffs_skip_rest_of_block(dev);
++ }
++ }
++ return YAFFS_OK;
++}
++
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block)
++{
++ struct yaffs_packed_tags2_tags_only tags_only;
++ struct yaffs_summary_tags *sum_tags;
++ if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
++ sum_tags = &dev->sum_tags[chunk_in_block];
++ tags_only.chunk_id = sum_tags->chunk_id;
++ tags_only.n_bytes = sum_tags->n_bytes;
++ tags_only.obj_id = sum_tags->obj_id;
++ yaffs_unpack_tags2_tags_only(tags, &tags_only);
++ return YAFFS_OK;
++ }
++ return YAFFS_FAIL;
++}
++
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
++ int i;
++
++ if (!bi->has_summary)
++ return;
++
++ for (i = dev->chunks_per_summary;
++ i < dev->param.chunks_per_block;
++ i++) {
++ if (yaffs_check_chunk_bit(dev, blk, i)) {
++ yaffs_clear_chunk_bit(dev, blk, i);
++ bi->pages_in_use--;
++ dev->n_free_chunks++;
++ }
++ }
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_summary.h linux-3.4.90/fs/yaffs2/yaffs_summary.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_summary.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_summary.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_SUMMARY_H__
++#define __YAFFS_SUMMARY_H__
++
++#include "yaffs_packedtags2.h"
++
++
++int yaffs_summary_init(struct yaffs_dev *dev);
++void yaffs_summary_deinit(struct yaffs_dev *dev);
++
++int yaffs_summary_add(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_fetch(struct yaffs_dev *dev,
++ struct yaffs_ext_tags *tags,
++ int chunk_in_block);
++int yaffs_summary_read(struct yaffs_dev *dev,
++ struct yaffs_summary_tags *st,
++ int blk);
++void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
++
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.4.90/fs/yaffs2/yaffs_tagscompat.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_tagscompat.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,381 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++
++
++/********** Tags ECC calculations *********/
++
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
++{
++ /* Calculate an ecc */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++ unsigned i, j;
++ unsigned ecc = 0;
++ unsigned bit = 0;
++
++ tags->ecc = 0;
++
++ for (i = 0; i < 8; i++) {
++ for (j = 1; j & 0xff; j <<= 1) {
++ bit++;
++ if (b[i] & j)
++ ecc ^= bit;
++ }
++ }
++ tags->ecc = ecc;
++}
++
++int yaffs_check_tags_ecc(struct yaffs_tags *tags)
++{
++ unsigned ecc = tags->ecc;
++
++ yaffs_calc_tags_ecc(tags);
++
++ ecc ^= tags->ecc;
++
++ if (ecc && ecc <= 64) {
++ /* TODO: Handle the failure better. Retire? */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++
++ ecc--;
++
++ b[ecc / 8] ^= (1 << (ecc & 7));
++
++ /* Now recvalc the ecc */
++ yaffs_calc_tags_ecc(tags);
++
++ return 1; /* recovered error */
++ } else if (ecc) {
++ /* Wierd ecc failure value */
++ /* TODO Need to do somethiong here */
++ return -1; /* unrecovered error */
++ }
++ return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++
++ yaffs_calc_tags_ecc(tags_ptr);
++
++ spare_ptr->tb0 = tu->as_bytes[0];
++ spare_ptr->tb1 = tu->as_bytes[1];
++ spare_ptr->tb2 = tu->as_bytes[2];
++ spare_ptr->tb3 = tu->as_bytes[3];
++ spare_ptr->tb4 = tu->as_bytes[4];
++ spare_ptr->tb5 = tu->as_bytes[5];
++ spare_ptr->tb6 = tu->as_bytes[6];
++ spare_ptr->tb7 = tu->as_bytes[7];
++}
++
++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
++ struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++ int result;
++
++ tu->as_bytes[0] = spare_ptr->tb0;
++ tu->as_bytes[1] = spare_ptr->tb1;
++ tu->as_bytes[2] = spare_ptr->tb2;
++ tu->as_bytes[3] = spare_ptr->tb3;
++ tu->as_bytes[4] = spare_ptr->tb4;
++ tu->as_bytes[5] = spare_ptr->tb5;
++ tu->as_bytes[6] = spare_ptr->tb6;
++ tu->as_bytes[7] = spare_ptr->tb7;
++
++ result = yaffs_check_tags_ecc(tags_ptr);
++ if (result > 0)
++ dev->n_tags_ecc_fixed++;
++ else if (result < 0)
++ dev->n_tags_ecc_unfixed++;
++}
++
++static void yaffs_spare_init(struct yaffs_spare *spare)
++{
++ memset(spare, 0xff, sizeof(struct yaffs_spare));
++}
++
++static int yaffs_wr_nand(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ struct yaffs_spare *spare)
++{
++ int data_size = dev->data_bytes_per_chunk;
++
++ return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, sizeof(*spare));
++}
++
++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data,
++ struct yaffs_spare *spare,
++ enum yaffs_ecc_result *ecc_result,
++ int correct_errors)
++{
++ int ret_val;
++ struct yaffs_spare local_spare;
++ int data_size;
++ int spare_size;
++ int ecc_result1, ecc_result2;
++ u8 calc_ecc[3];
++
++ if (!spare) {
++ /* If we don't have a real spare, then we use a local one. */
++ /* Need this for the calculation of the ecc */
++ spare = &local_spare;
++ }
++ data_size = dev->data_bytes_per_chunk;
++ spare_size = sizeof(struct yaffs_spare);
++
++ if (dev->param.use_nand_ecc)
++ return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *) spare, spare_size,
++ ecc_result);
++
++
++ /* Handle the ECC at this level. */
++
++ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, data_size,
++ (u8 *)spare, spare_size,
++ NULL);
++ if (!data || !correct_errors)
++ return ret_val;
++
++ /* Do ECC correction if needed. */
++ yaffs_ecc_calc(data, calc_ecc);
++ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
++ yaffs_ecc_calc(&data[256], calc_ecc);
++ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
++
++ if (ecc_result1 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result1 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:0",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result2 > 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error fix performed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_fixed++;
++ } else if (ecc_result2 < 0) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "**>>yaffs ecc error unfixed on chunk %d:1",
++ nand_chunk);
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result1 || ecc_result2) {
++ /* We had a data problem on this page */
++ yaffs_handle_rd_data_error(dev, nand_chunk);
++ }
++
++ if (ecc_result1 < 0 || ecc_result2 < 0)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ else if (ecc_result1 > 0 || ecc_result2 > 0)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ else
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ return ret_val;
++}
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++
++ /* Mark the block for retirement */
++ yaffs_get_block_info(dev, flash_block + dev->block_offset)->
++ needs_retiring = 1;
++ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ "**>>Block %d marked for retirement",
++ flash_block);
++
++ /* TODO:
++ * Just do a garbage collection on the affected block
++ * then retire the block
++ * NB recursion
++ */
++}
++
++static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++
++ yaffs_spare_init(&spare);
++
++ if (ext_tags->is_deleted)
++ spare.page_status = 0;
++ else {
++ tags.obj_id = ext_tags->obj_id;
++ tags.chunk_id = ext_tags->chunk_id;
++
++ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
++ else
++ tags.n_bytes_msb = 3;
++
++ tags.serial_number = ext_tags->serial_number;
++
++ if (!dev->param.use_nand_ecc && data) {
++ yaffs_ecc_calc(data, spare.ecc1);
++ yaffs_ecc_calc(&data[256], spare.ecc2);
++ }
++
++ yaffs_load_tags_to_spare(&spare, &tags);
++ }
++ return yaffs_wr_nand(dev, nand_chunk, data, &spare);
++}
++
++static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ int deleted;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ if (!yaffs_rd_chunk_nand(dev, nand_chunk,
++ data, &spare, &ecc_result, 1))
++ return YAFFS_FAIL;
++
++ /* ext_tags may be NULL */
++ if (!ext_tags)
++ return YAFFS_OK;
++
++ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
++
++ ext_tags->is_deleted = deleted;
++ ext_tags->ecc_result = ecc_result;
++ ext_tags->block_bad = 0; /* We're reading it */
++ /* therefore it is not a bad block */
++ ext_tags->chunk_used =
++ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
++
++ if (ext_tags->chunk_used) {
++ yaffs_get_tags_from_spare(dev, &spare, &tags);
++ ext_tags->obj_id = tags.obj_id;
++ ext_tags->chunk_id = tags.chunk_id;
++ ext_tags->n_bytes = tags.n_bytes_lsb;
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ ext_tags->n_bytes |=
++ (((unsigned)tags.n_bytes_msb) << 10);
++
++ ext_tags->serial_number = tags.serial_number;
++ }
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_spare spare;
++
++ memset(&spare, 0xff, sizeof(struct yaffs_spare));
++
++ spare.block_status = 'Y';
++
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
++ &spare);
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
++ NULL, &spare);
++
++ return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ struct yaffs_spare spare0, spare1;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ enum yaffs_ecc_result dummy;
++
++ if (!init) {
++ memset(&spare_ff, 0xff, sizeof(spare_ff));
++ init = 1;
++ }
++
++ *seq_number = 0;
++
++ /* Look for bad block markers in the first two chunks */
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
++ NULL, &spare0, &dummy, 0);
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
++ NULL, &spare1, &dummy, 0);
++
++ if (hweight8(spare0.block_status & spare1.block_status) < 7)
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ else
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++
++ return YAFFS_OK;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++ if(dev->param.is_yaffs2)
++ return;
++ if(!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
++ if(!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
++ if(!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++ if(!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.4.90/fs/yaffs2/yaffs_tagscompat.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_tagscompat.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++
++#include "yaffs_guts.h"
++
++#if 0
++
++
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 *data, const struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 *data, struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number);
++
++#endif
++
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev);
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
++int yaffs_check_tags_ecc(struct yaffs_tags *tags);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,199 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_packedtags2.h"
++
++static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
++ int nand_chunk, const u8 *data,
++ const struct yaffs_ext_tags *tags)
++{
++ struct yaffs_packed_tags2 pt;
++ int retval;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_write chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ /* For yaffs2 writing there must be both data and tags.
++ * If we're using inband tags, then the tags are stuffed into
++ * the end of the data buffer.
++ */
++ if (!data || !tags)
++ BUG();
++ else if (dev->param.inband_tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)(data +
++ dev->
++ data_bytes_per_chunk);
++ yaffs_pack_tags2_tags_only(pt2tp, tags);
++ } else {
++ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
++ }
++
++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ (dev->param.inband_tags) ? NULL : packed_tags_ptr,
++ (dev->param.inband_tags) ? 0 : packed_tags_size);
++
++ return retval;
++}
++
++static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
++ int nand_chunk, u8 *data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = 0;
++ int local_data = 0;
++ u8 spare_buffer[100];
++ enum yaffs_ecc_result ecc_result;
++
++ struct yaffs_packed_tags2 pt;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "yaffs_tags_marshall_read chunk %d data %p tags %p",
++ nand_chunk, data, tags);
++
++ if (dev->param.inband_tags) {
++ if (!data) {
++ local_data = 1;
++ data = yaffs_get_temp_buffer(dev);
++ }
++ }
++
++ if (dev->param.inband_tags || (data && !tags))
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ NULL, 0,
++ &ecc_result);
++ else if (tags)
++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++ data, dev->param.total_bytes_per_chunk,
++ spare_buffer, packed_tags_size,
++ &ecc_result);
++ else
++ BUG();
++
++
++ if (dev->param.inband_tags) {
++ if (tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)
++ &data[dev->data_bytes_per_chunk];
++ yaffs_unpack_tags2_tags_only(tags, pt2tp);
++ }
++ } else if (tags) {
++ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
++ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
++ }
++
++ if (local_data)
++ yaffs_release_temp_buffer(dev, data);
++
++ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ dev->n_ecc_unfixed++;
++ }
++
++ if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
++ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ }
++
++ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state,
++ u32 *seq_number)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
++ block_no);
++
++ retval = dev->drv.drv_check_bad_fn(dev, block_no);
++
++ if (retval== YAFFS_FAIL) {
++ yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
++
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ *seq_number = 0;
++ } else {
++ struct yaffs_ext_tags t;
++
++ yaffs_tags_marshall_read(dev,
++ block_no * dev->param.chunks_per_block,
++ NULL, &t);
++
++ if (t.chunk_used) {
++ *seq_number = t.seq_number;
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++ } else {
++ *seq_number = 0;
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++ }
++
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "block query returns seq %d state %d",
++ *seq_number, *state);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ return dev->drv.drv_mark_bad_fn(dev, block_no);
++
++}
++
++
++void yaffs_tags_marshall_install(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->tagger.write_chunk_tags_fn)
++ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
++
++ if (!dev->tagger.read_chunk_tags_fn)
++ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
++
++ if (!dev->tagger.query_block_fn)
++ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
++
++ if (!dev->tagger.mark_bad_fn)
++ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
++
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_tagsmarshall.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSMARSHALL_H__
++#define __YAFFS_TAGSMARSHALL_H__
++
++#include "yaffs_guts.h"
++void yaffs_tags_marshall_install(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_trace.h linux-3.4.90/fs/yaffs2/yaffs_trace.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_trace.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_trace_mask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS 0x00000002
++#define YAFFS_TRACE_ALLOCATE 0x00000004
++#define YAFFS_TRACE_SCAN 0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
++#define YAFFS_TRACE_ERASE 0x00000020
++#define YAFFS_TRACE_GC 0x00000040
++#define YAFFS_TRACE_WRITE 0x00000080
++#define YAFFS_TRACE_TRACING 0x00000100
++#define YAFFS_TRACE_DELETION 0x00000200
++#define YAFFS_TRACE_BUFFERS 0x00000400
++#define YAFFS_TRACE_NANDACCESS 0x00000800
++#define YAFFS_TRACE_GC_DETAIL 0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
++#define YAFFS_TRACE_MTD 0x00004000
++#define YAFFS_TRACE_CHECKPOINT 0x00008000
++
++#define YAFFS_TRACE_VERIFY 0x00010000
++#define YAFFS_TRACE_VERIFY_NAND 0x00020000
++#define YAFFS_TRACE_VERIFY_FULL 0x00040000
++#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
++
++#define YAFFS_TRACE_SYNC 0x00100000
++#define YAFFS_TRACE_BACKGROUND 0x00200000
++#define YAFFS_TRACE_LOCK 0x00400000
++#define YAFFS_TRACE_MOUNT 0x00800000
++
++#define YAFFS_TRACE_ERROR 0x40000000
++#define YAFFS_TRACE_BUG 0x80000000
++#define YAFFS_TRACE_ALWAYS 0xf0000000
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_verify.c linux-3.4.90/fs/yaffs2/yaffs_verify.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_verify.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,529 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_verify.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++
++int yaffs_skip_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask &
++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_full_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
++{
++ (void) dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char * const block_state_name[] = {
++ "Unknown",
++ "Needs scan",
++ "Scanning",
++ "Empty",
++ "Allocating",
++ "Full",
++ "Dirty",
++ "Checkpoint",
++ "Collecting",
++ "Dead"
++};
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
++{
++ int actually_used;
++ int in_use;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Report illegal runtime states */
++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has undefined state %d",
++ n, bi->block_state);
++
++ switch (bi->block_state) {
++ case YAFFS_BLOCK_STATE_UNKNOWN:
++ case YAFFS_BLOCK_STATE_SCANNING:
++ case YAFFS_BLOCK_STATE_NEEDS_SCAN:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has bad run-state %s",
++ n, block_state_name[bi->block_state]);
++ }
++
++ /* Check pages in use and soft deletions are legal */
++
++ actually_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->pages_in_use < 0 ||
++ bi->pages_in_use > dev->param.chunks_per_block ||
++ bi->soft_del_pages < 0 ||
++ bi->soft_del_pages > dev->param.chunks_per_block ||
++ actually_used < 0 || actually_used > dev->param.chunks_per_block)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has illegal values pages_in_used %d soft_del_pages %d",
++ n, bi->pages_in_use, bi->soft_del_pages);
++
++ /* Check chunk bitmap legal */
++ in_use = yaffs_count_chunk_bits(dev, n);
++ if (in_use != bi->pages_in_use)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
++ n, bi->pages_in_use, in_use);
++}
++
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n)
++{
++ yaffs_verify_blk(dev, bi, n);
++
++ /* After collection the block should be in the erased state */
++
++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Block %d is in state %d after gc, should be erased",
++ n, bi->block_state);
++ }
++}
++
++void yaffs_verify_blocks(struct yaffs_dev *dev)
++{
++ int i;
++ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
++ int illegal_states = 0;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ memset(state_count, 0, sizeof(state_count));
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ yaffs_verify_blk(dev, bi, i);
++
++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
++ state_count[bi->block_state]++;
++ else
++ illegal_states++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
++
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%d blocks have illegal states",
++ illegal_states);
++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many allocating blocks");
++
++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "%s %d blocks",
++ block_state_name[i], state_count[i]);
++
++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Checkpoint block count wrong dev %d count %d",
++ dev->blocks_in_checkpt,
++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
++
++ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Erased block count wrong dev %d count %d",
++ dev->n_erased_blocks,
++ state_count[YAFFS_BLOCK_STATE_EMPTY]);
++
++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Too many collecting blocks %d (max is 1)",
++ state_count[YAFFS_BLOCK_STATE_COLLECTING]);
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in
++ * which case those tests will not be performed.
++ */
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!(tags && obj && oh)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Verifying object header tags %p obj %p oh %p",
++ tags, obj, oh);
++ return;
++ }
++
++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++ oh->type > YAFFS_OBJECT_TYPE_MAX)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header type is illegal value 0x%x",
++ tags->obj_id, oh->type);
++
++ if (tags->obj_id != obj->obj_id)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch obj_id %d",
++ tags->obj_id, obj->obj_id);
++
++ /*
++ * Check that the object's parent ids match if parent_check requested.
++ *
++ * Tests do not apply to the root object.
++ */
++
++ if (parent_check && tags->obj_id > 1 && !obj->parent)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d obj->parent is NULL",
++ tags->obj_id, oh->parent_obj_id);
++
++ if (parent_check && obj->parent &&
++ oh->parent_obj_id != obj->parent->obj_id &&
++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header mismatch parent_id %d parent_obj_id %d",
++ tags->obj_id, oh->parent_obj_id,
++ obj->parent->obj_id);
++
++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is NULL",
++ obj->obj_id);
++
++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d header name is 0xff",
++ obj->obj_id);
++}
++
++void yaffs_verify_file(struct yaffs_obj *obj)
++{
++ u32 x;
++ int required_depth;
++ int actual_depth;
++ int last_chunk;
++ u32 offset_in_chunk;
++ u32 the_chunk;
++
++ u32 i;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ struct yaffs_tnode *tn;
++ u32 obj_id;
++
++ if (!obj)
++ return;
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ dev = obj->my_dev;
++ obj_id = obj->obj_id;
++
++
++ /* Check file size is consistent with tnode depth */
++ yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
++ &last_chunk, &offset_in_chunk);
++ last_chunk++;
++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x > 0) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ actual_depth = obj->variant.file_variant.top_level;
++
++ /* Check that the chunks in the tnode tree are all correct.
++ * We do this by scanning through the tnode tree and
++ * checking the tags for every chunk match.
++ */
++
++ if (yaffs_skip_nand_verification(dev))
++ return;
++
++ for (i = 1; i <= last_chunk; i++) {
++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
++
++ if (!tn)
++ continue;
++
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk > 0) {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ &tags);
++ if (tags.obj_id != obj_id || tags.chunk_id != i)
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
++ obj_id, i, the_chunk,
++ tags.obj_id, tags.chunk_id);
++ }
++ }
++}
++
++void yaffs_verify_link(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify sane equivalent object */
++}
++
++void yaffs_verify_symlink(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify symlink string */
++}
++
++void yaffs_verify_special(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++}
++
++void yaffs_verify_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++ u32 chunk_min;
++ u32 chunk_max;
++ u32 chunk_id_ok;
++ u32 chunk_in_range;
++ u32 chunk_wrongly_deleted;
++ u32 chunk_valid;
++
++ if (!obj)
++ return;
++
++ if (obj->being_created)
++ return;
++
++ dev = obj->my_dev;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Check sane object header chunk */
++
++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
++ chunk_max =
++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
++
++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
++ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
++ chunk_valid = chunk_in_range &&
++ yaffs_check_chunk_bit(dev,
++ obj->hdr_chunk / dev->param.chunks_per_block,
++ obj->hdr_chunk % dev->param.chunks_per_block);
++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
++
++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has chunk_id %d %s %s",
++ obj->obj_id, obj->hdr_chunk,
++ chunk_id_ok ? "" : ",out of range",
++ chunk_wrongly_deleted ? ",marked as deleted" : "");
++
++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj_hdr *oh;
++ u8 *buffer = yaffs_get_temp_buffer(dev);
++
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
++
++ yaffs_verify_oh(obj, oh, &tags, 1);
++
++ yaffs_release_temp_buffer(dev, buffer);
++ }
++
++ /* Verify it has a parent */
++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has parent pointer %p which does not look like an object",
++ obj->obj_id, obj->parent);
++ }
++
++ /* Verify parent is a directory */
++ if (obj->parent &&
++ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d's parent is not a directory (type %d)",
++ obj->obj_id, obj->parent->variant_type);
++ }
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ yaffs_verify_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ yaffs_verify_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ yaffs_verify_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ yaffs_verify_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ yaffs_verify_special(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ yaffs_trace(YAFFS_TRACE_VERIFY,
++ "Obj %d has illegaltype %d",
++ obj->obj_id, obj->variant_type);
++ break;
++ }
++}
++
++void yaffs_verify_objects(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int i;
++ struct list_head *lh;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Iterate through the objects in each hash entry */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ yaffs_verify_obj(obj);
++ }
++ }
++}
++
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++ int count = 0;
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!obj->parent) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
++ BUG();
++ return;
++ }
++
++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_verify_obj(list_obj);
++ if (obj == list_obj)
++ count++;
++ }
++
++ if (count != 1) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory %d times",
++ count);
++ BUG();
++ }
++}
++
++void yaffs_verify_dir(struct yaffs_obj *directory)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++
++ if (!directory) {
++ BUG();
++ return;
++ }
++
++ if (yaffs_skip_full_verification(directory->my_dev))
++ return;
++
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Directory has wrong type: %d",
++ directory->variant_type);
++ BUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &directory->variant.dir_variant.children) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (list_obj->parent != directory) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Object in directory list has wrong parent %p",
++ list_obj->parent);
++ BUG();
++ }
++ yaffs_verify_obj_in_dir(list_obj);
++ }
++}
++
++static int yaffs_free_verification_failures;
++
++void yaffs_verify_free_chunks(struct yaffs_dev *dev)
++{
++ int counted;
++ int difference;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ counted = yaffs_count_free_chunks(dev);
++
++ difference = dev->n_free_chunks - counted;
++
++ if (difference) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Freechunks verification failure %d %d %d",
++ dev->n_free_chunks, counted, difference);
++ yaffs_free_verification_failures++;
++ }
++}
++
++int yaffs_verify_file_sane(struct yaffs_obj *in)
++{
++ (void) in;
++ return YAFFS_OK;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_verify.h linux-3.4.90/fs/yaffs2/yaffs_verify.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_verify.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_VERIFY_H__
++#define __YAFFS_VERIFY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
++ int n);
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n);
++void yaffs_verify_blocks(struct yaffs_dev *dev);
++
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check);
++void yaffs_verify_file(struct yaffs_obj *obj);
++void yaffs_verify_link(struct yaffs_obj *obj);
++void yaffs_verify_symlink(struct yaffs_obj *obj);
++void yaffs_verify_special(struct yaffs_obj *obj);
++void yaffs_verify_obj(struct yaffs_obj *obj);
++void yaffs_verify_objects(struct yaffs_dev *dev);
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
++void yaffs_verify_dir(struct yaffs_obj *directory);
++void yaffs_verify_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_verify_file_sane(struct yaffs_obj *obj);
++
++int yaffs_skip_verification(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_vfs.c linux-3.4.90/fs/yaffs2/yaffs_vfs.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_vfs.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,3600 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * 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 struct yaffs_dev associated with
++ * this superblock
++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
++ * superblock
++ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
++ */
++
++/*
++ * There are two variants of the VFS glue code. This variant should compile
++ * for any version of Linux.
++ */
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
++#define YAFFS_COMPILE_BACKGROUND
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
++#define YAFFS_COMPILE_FREEZER
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
++#define YAFFS_COMPILE_EXPORTFS
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_USE_SETATTR_COPY
++#define YAFFS_USE_TRUNCATE_SETSIZE
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
++#define YAFFS_HAS_EVICT_INODE
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++#define YAFFS_NEW_FOLLOW_LINK 1
++#else
++#define YAFFS_NEW_FOLLOW_LINK 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_HAS_WRITE_SUPER
++#endif
++
++
++#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/fs.h>
++#include <linux/proc_fs.h>
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
++#include <linux/smp_lock.h>
++#endif
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++#include <linux/namei.h>
++#endif
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++#include <linux/exportfs.h>
++#endif
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#endif
++#ifdef YAFFS_COMPILE_FREEZER
++#include <linux/freezer.h>
++#endif
++
++#include <asm/div64.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/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, 26))
++#define YPROC_ROOT (&proc_root)
++#else
++#define YPROC_ROOT NULL
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define Y_INIT_TIMER(a) init_timer(a)
++#else
++#define Y_INIT_TIMER(a) init_timer_on_stack(a)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
++#define YAFFS_SUPER_HAS_DIRTY
++#endif
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
++#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++ uint64_t result = partition_size;
++ do_div(result, block_size);
++ return (uint32_t) result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/mtd/mtd.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#include "yaffs_linux.h"
++
++#include "yaffs_mtdif.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_getblockinfo.h"
++
++unsigned int yaffs_trace_mask =
++ YAFFS_TRACE_BAD_BLOCKS |
++ YAFFS_TRACE_ALWAYS |
++ 0;
++
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++unsigned int yaffs_gc_control = 1;
++unsigned int yaffs_bg_enable = 1;
++unsigned int yaffs_auto_select = 1;
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_trace_mask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++module_param(yaffs_gc_control, uint, 0644);
++module_param(yaffs_bg_enable, uint, 0644);
++#else
++MODULE_PARM(yaffs_trace_mask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++MODULE_PARM(yaffs_gc_control, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
++#else
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_inode_to_obj(iptr) \
++ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
++#else
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define Y_CLEAR_INODE(i) clear_inode(i)
++#else
++#define Y_CLEAR_INODE(i) end_writeback(i)
++#endif
++
++
++#define update_dir_time(dir) do {\
++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++ } while (0)
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj);
++
++
++static void yaffs_gross_lock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
++}
++
++static void yaffs_gross_unlock(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
++}
++
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++ /* Lifted from jffs2 */
++
++ struct yaffs_obj *obj;
++ unsigned char *pg_buf;
++ int ret;
++ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readpage_nolock at %lld, size %08x",
++ (long long)pos,
++ (unsigned)PAGE_CACHE_SIZE);
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++#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_gross_lock(dev);
++
++ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
++
++ yaffs_gross_unlock(dev);
++
++ if (ret >= 0)
++ ret = 0;
++
++ if (ret) {
++ ClearPageUptodate(pg);
++ SetPageError(pg);
++ } else {
++ SetPageUptodate(pg);
++ ClearPageError(pg);
++ }
++
++ flush_dcache_page(pg);
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
++ 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)
++{
++ int ret;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
++ ret = yaffs_readpage_unlock(f, pg);
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
++ return ret;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid())
++#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid())
++#else
++#define YCRED_FSUID() YCRED(current)->fsuid
++#define YCRED_FSGID() YCRED(current)->fsgid
++
++static inline uid_t i_uid_read(const struct inode *inode)
++{
++ return inode->i_uid;
++}
++
++static inline gid_t i_gid_read(const struct inode *inode)
++{
++ return inode->i_gid;
++}
++
++static inline void i_uid_write(struct inode *inode, uid_t uid)
++{
++ inode->i_uid = uid;
++}
++
++static inline void i_gid_write(struct inode *inode, gid_t gid)
++{
++ inode->i_gid = gid;
++}
++#endif
++
++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc)
++ lc->dirty = val;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb)
++ sb->s_dirt = val;
++ }
++#endif
++
++}
++
++static void yaffs_set_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 1);
++}
++
++static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
++{
++ yaffs_set_super_dirty_val(dev, 0);
++}
++
++static int yaffs_check_super_dirty(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
++
++ if (lc && lc->dirty)
++ return 1;
++
++# ifdef YAFFS_SUPER_HAS_DIRTY
++ {
++ struct super_block *sb = lc->super;
++
++ if (sb && sb->s_dirt)
++ return 1;
++ }
++#endif
++ return 0;
++
++}
++
++#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 yaffs_dev *dev;
++ struct address_space *mapping = page->mapping;
++ struct inode *inode;
++ unsigned long end_index;
++ char *buffer;
++ struct yaffs_obj *obj;
++ int n_written = 0;
++ unsigned n_bytes;
++ loff_t i_size;
++
++ if (!mapping)
++ BUG();
++ inode = mapping->host;
++ if (!inode)
++ BUG();
++ i_size = i_size_read(inode);
++
++ end_index = i_size >> PAGE_CACHE_SHIFT;
++
++ if (page->index < end_index)
++ n_bytes = PAGE_CACHE_SIZE;
++ else {
++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
++
++ if (page->index > end_index || !n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, inode size = %lld!!",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
++ inode->i_size);
++ yaffs_trace(YAFFS_TRACE_OS,
++ " -> don't care!!");
++
++ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ return 0;
++ }
++ }
++
++ if (n_bytes != PAGE_CACHE_SIZE)
++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
++
++ get_page(page);
++
++ buffer = kmap(page);
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_writepage at %lld, size %08x",
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag0: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ n_written = yaffs_wr_file(obj, buffer,
++ ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "writepag1: obj = %lld, ino = %lld",
++ obj->variant.file_variant.file_size, inode->i_size);
++
++ yaffs_gross_unlock(dev);
++
++ kunmap(page);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ put_page(page);
++
++ return (n_written == n_bytes) ? 0 : -ENOSPC;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ int n_free_chunks;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ n_free_chunks = yaffs_get_n_free_chunks(dev);
++
++ yaffs_gross_unlock(dev);
++
++ return (n_free_chunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_gross_unlock(dev);
++}
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{
++ struct page *pg = NULL;
++ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++ int ret = 0;
++ int space_held = 0;
++
++ /* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++ pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++ pg = __grab_cache_page(mapping, index);
++#endif
++
++ *pagep = pg;
++ if (!pg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "start yaffs_write_begin index %d(%x) uptodate %d",
++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
++
++ /* Get fs space */
++ space_held = yaffs_hold_space(filp);
++
++ if (!space_held) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ /* Update page if required */
++
++ if (!Page_Uptodate(pg))
++ ret = yaffs_readpage_nolock(filp, pg);
++
++ if (ret)
++ goto out;
++
++ /* Happy path return */
++ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
++
++ return 0;
++
++out:
++ yaffs_trace(YAFFS_TRACE_OS,
++ "end yaffs_write_begin fail returning %d", ret);
++ if (space_held)
++ yaffs_release_space(filp);
++ if (pg) {
++ unlock_page(pg);
++ page_cache_release(pg);
++ }
++ return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to)
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
++
++ if (!Page_Uptodate(pg))
++ return yaffs_readpage_nolock(f, pg);
++ return 0;
++}
++#endif
++
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t * pos)
++{
++ struct yaffs_obj *obj;
++ int n_written;
++ loff_t ipos;
++ struct inode *inode;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: hey obj is null!");
++ return -EINVAL;
++ }
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
++ (unsigned)n, (unsigned)n, obj->obj_id, ipos);
++
++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
++
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write: %d(%x) bytes written",
++ (unsigned)n, (unsigned)n);
++
++ if (n_written > 0) {
++ ipos += n_written;
++ *pos = ipos;
++ if (ipos > inode->i_size) {
++ inode->i_size = ipos;
++ inode->i_blocks = (ipos + 511) >> 9;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_write size updated to %lld bytes, %d blocks",
++ ipos, (int)(inode->i_blocks));
++ }
++
++ }
++ yaffs_gross_unlock(dev);
++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
++}
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata)
++{
++ int ret = 0;
++ void *addr, *kva;
++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++ kva = kmap(pg);
++ addr = kva + offset_into_page;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end addr %p pos %lld n_bytes %d",
++ addr, pos, copied);
++
++ ret = yaffs_file_write(filp, addr, copied, &pos);
++
++ if (ret != copied) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_write_end not same size ret %d copied %d",
++ ret, copied);
++ SetPageError(pg);
++ }
++
++ kunmap(pg);
++
++ yaffs_release_space(filp);
++ unlock_page(pg);
++ page_cache_release(pg);
++ return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to)
++{
++ void *addr, *kva;
++
++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++ int n_bytes = to - offset;
++ int n_written;
++
++ kva = kmap(pg);
++ addr = kva + offset;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write addr %p pos %lld n_bytes %d",
++ addr, pos, n_bytes);
++
++ n_written = yaffs_file_write(f, addr, n_bytes, &pos);
++
++ if (n_written != n_bytes) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write not same size n_written %d n_bytes %d",
++ n_written, n_bytes);
++ SetPageError(pg);
++ }
++ kunmap(pg);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_commit_write returning %d",
++ n_written == n_bytes ? 0 : n_written);
++
++ return n_written == n_bytes ? 0 : n_written;
++}
++#endif
++
++static struct address_space_operations yaffs_file_address_operations = {
++ .readpage = yaffs_readpage,
++ .writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++ .write_begin = yaffs_write_begin,
++ .write_end = yaffs_write_end,
++#else
++ .prepare_write = yaffs_prepare_write,
++ .commit_write = yaffs_commit_write,
++#endif
++};
++
++
++#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
++{
++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_file_flush object %d (%s)",
++ obj->obj_id,
++ obj->dirty ? "dirty" : "clean");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_file(obj, 1, 0);
++
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync)
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync)
++#endif
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++ struct dentry *dentry = file->f_path.dentry;
++#endif
++
++ obj = yaffs_dentry_to_obj(dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_object");
++ yaffs_gross_lock(dev);
++ yaffs_flush_file(obj, 1, datasync);
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const 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,
++ .llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const 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 const 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
++
++
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++ void *kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + start, 0, end - start);
++ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(page);
++}
++#endif
++
++
++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
++{
++#ifdef YAFFS_USE_TRUNCATE_SETSIZE
++ truncate_setsize(inode, newsize);
++ return 0;
++#else
++ truncate_inode_pages(&inode->i_data, newsize);
++ return 0;
++#endif
++
++}
++
++
++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
++{
++#ifdef YAFFS_USE_SETATTR_COPY
++ setattr_copy(inode, attr);
++ return 0;
++#else
++ return inode_setattr(inode, attr);
++#endif
++
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_setattr of object %d",
++ yaffs_inode_to_obj(inode)->obj_id);
++#if 0
++ /* Fail if a requested resize >= 2GB */
++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
++ error = -EINVAL;
++#endif
++
++ if (error == 0)
++ error = inode_change_ok(inode, attr);
++ if (error == 0) {
++ int result;
++ if (!error) {
++ error = yaffs_vfs_setattr(inode, attr);
++ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_vfs_setsize(inode, attr->ia_size);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++ }
++ }
++ dev = yaffs_inode_to_obj(inode)->my_dev;
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "resize to %d(%x)",
++ (int)(attr->ia_size),
++ (int)(attr->ia_size));
++ }
++ yaffs_gross_lock(dev);
++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
++ if (result == YAFFS_OK) {
++ error = 0;
++ } else {
++ error = -EPERM;
++ }
++ yaffs_gross_unlock(dev);
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_set_xattrib(obj, name, value, size, flags);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
++ void *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_getxattr \"%s\" from object %d",
++ name, obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_get_xattrib(obj, name, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
++
++ return error;
++}
++
++static int yaffs_removexattr(struct dentry *dentry, const char *name)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_remove_xattrib(obj, name);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_removexattr done returning %d", error);
++
++ return error;
++}
++
++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr of object %d", obj->obj_id);
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_list_xattrib(obj, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_listxattr done returning %d", error);
++
++ return error;
++}
++
++
++static const struct inode_operations yaffs_file_inode_operations = {
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++ int buflen)
++{
++ unsigned char *alias;
++ int ret;
++
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++
++ yaffs_gross_unlock(dev);
++
++ if (!alias)
++ return -ENOMEM;
++
++ ret = vfs_readlink(dentry, buffer, buflen, alias);
++ kfree(alias);
++ return ret;
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ void *ret;
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int ret
++#endif
++ unsigned char *alias;
++ int ret_int = 0;
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++ yaffs_gross_unlock(dev);
++
++ if (!alias) {
++ ret_int = -ENOMEM;
++ goto out;
++ }
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ nd_set_link(nd, alias);
++ ret = alias;
++out:
++ if (ret_int)
++ ret = ERR_PTR(ret_int);
++ return ret;
++#else
++ ret = vfs_follow_link(nd, alias);
++ kfree(alias);
++out:
++ if (ret_int)
++ ret = ret_int;
++ return ret;
++#endif
++}
++
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* 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)
++{
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_put_inode: ino %d, count %d"),
++ (int)inode->i_ino, atomic_read(&inode->i_count);
++
++}
++#endif
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++{
++ kfree(alias);
++}
++#endif
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++ .readlink = yaffs_readlink,
++ .follow_link = yaffs_follow_link,
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ .put_link = yaffs_put_link,
++#endif
++ .setattr = yaffs_setattr,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++ struct inode *inode;
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return 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_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ yaffs_gross_unlock(dev);
++
++ unlock_new_inode(inode);
++ return inode;
++}
++
++#else
++
++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.
++ */
++
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_inode for %d", (int)inode->i_ino);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++}
++
++#endif
++
++
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ struct yaffs_obj *obj)
++{
++ struct inode *inode;
++
++ if (!sb) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL super_block!!");
++ return NULL;
++
++ }
++
++ if (!obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for NULL object!!");
++ return NULL;
++
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_get_inode for object %d", obj->obj_id);
++
++ inode = Y_IGET(sb, obj->obj_id);
++ if (IS_ERR(inode))
++ return NULL;
++
++ /* NB Side effect: iget calls back to yaffs_read_inode(). */
++ /* iget also increments the inode's i_count */
++ /* NB You can't be holding gross_lock or deadlock will happen! */
++
++ return inode;
++}
++
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++ dev_t rdev)
++#elif (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;
++
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_dev *dev;
++
++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
++
++ int error = -ENOSPC;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++ mode |= S_ISGID;
++
++ if (parent) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: parent object %d type %d",
++ parent->obj_id, parent->variant_type);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: could not get parent object");
++ return -EPERM;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod: making oject for %s, mode %x dev %x",
++ dentry->d_name.name, mode, rdev);
++
++ dev = parent->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ switch (mode & S_IFMT) {
++ default:
++ /* Special (socket, fifo, device...) */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, old_encode_dev(rdev));
++#else
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, rdev);
++#endif
++ break;
++ case S_IFREG: /* file */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
++ gid);
++ break;
++ case S_IFDIR: /* directory */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
++ uid, gid);
++ break;
++ case S_IFLNK: /* symlink */
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
++ obj = NULL; /* Do we ever get here? */
++ break;
++ }
++
++ /* Can not call yaffs_get_inode() with gross lock held */
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_mknod created object %d count = %d",
++ obj->obj_id, atomic_read(&inode->i_count));
++ error = 0;
++ yaffs_fill_inode_from_obj(dir, parent);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
++ error = -ENOMEM;
++ }
++
++ return error;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++#else
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++ int ret_val;
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++ return ret_val;
++}
++
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ bool dummy)
++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++ struct nameidata *n)
++#elif (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
++{
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ unsigned int dummy)
++#elif (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
++{
++ struct yaffs_obj *obj;
++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
++
++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
++
++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
++
++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
++
++ /* Can't hold gross lock when calling yaffs_get_inode() */
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_lookup found %d", obj->obj_id);
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
++
++ }
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *link = NULL;
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
++ link =
++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ obj);
++
++ if (link) {
++ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
++ d_instantiate(dentry, old_dentry->d_inode);
++ atomic_inc(&old_dentry->d_inode->i_count);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_link link count %d i_count %d",
++ old_dentry->d_inode->i_nlink,
++ atomic_read(&old_dentry->d_inode->i_count));
++ }
++
++ yaffs_gross_unlock(dev);
++
++ if (link) {
++ update_dir_time(dir);
++ return 0;
++ }
++
++ return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ uid_t uid = YCRED_FSUID();
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
++
++ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ return -ENAMETOOLONG;
++
++ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
++ YAFFS_MAX_ALIAS_LENGTH)
++ return -ENAMETOOLONG;
++
++ dev = yaffs_inode_to_obj(dir)->my_dev;
++ yaffs_gross_lock(dev);
++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ S_IFLNK | S_IRWXUGO, uid, gid, symname);
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ struct inode *inode;
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
++ return 0;
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
++ }
++
++ return -ENOMEM;
++}
++
++/*
++ * 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)
++{
++ struct yaffs_dev *dev;
++ int ret_val = YAFFS_FAIL;
++ struct yaffs_obj *target;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
++ dev = yaffs_inode_to_obj(old_dir)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ /* Check if the target is an existing directory that is not empty. */
++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++
++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !list_empty(&target->variant.dir_variant.children)) {
++
++ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
++
++ ret_val = YAFFS_FAIL;
++ } else {
++ /* Now does unlinking internally using shadowing mechanism */
++ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
++
++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
++ old_dentry->d_name.name,
++ yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++ }
++ yaffs_gross_unlock(dev);
++
++ if (ret_val == YAFFS_OK) {
++ if (target)
++ inode_dec_link_count(new_dentry->d_inode);
++
++ update_dir_time(old_dir);
++ if (old_dir != new_dir)
++ update_dir_time(new_dir);
++ return 0;
++ } else {
++ return -ENOTEMPTY;
++ }
++}
++
++
++
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int ret_val;
++
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
++ (int)(dir->i_ino), dentry->d_name.name);
++ obj = yaffs_inode_to_obj(dir);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ ret_val = yaffs_unlinker(obj, dentry->d_name.name);
++
++ if (ret_val == YAFFS_OK) {
++ inode_dec_link_count(dentry->d_inode);
++ dir->i_version++;
++ yaffs_gross_unlock(dev);
++ update_dir_time(dir);
++ return 0;
++ }
++ yaffs_gross_unlock(dev);
++ return -ENOTEMPTY;
++}
++
++
++
++static const 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,
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++};
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the remove_obj_fn to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each struct yaffs_dev has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_search_context {
++ struct yaffs_dev *dev;
++ struct yaffs_obj *dir_obj;
++ struct yaffs_obj *next_return;
++ struct list_head others;
++};
++
++/*
++ * yaffs_new_search() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
++{
++ struct yaffs_dev *dev = dir->my_dev;
++ struct yaffs_search_context *sc =
++ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
++ if (sc) {
++ sc->dir_obj = dir;
++ sc->dev = dev;
++ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else
++ sc->next_return =
++ list_entry(dir->variant.dir_variant.children.next,
++ struct yaffs_obj, siblings);
++ INIT_LIST_HEAD(&sc->others);
++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
++ }
++ return sc;
++}
++
++/*
++ * yaffs_search_end() disposes of a search context and cleans up.
++ */
++static void yaffs_search_end(struct yaffs_search_context *sc)
++{
++ if (sc) {
++ list_del(&sc->others);
++ kfree(sc);
++ }
++}
++
++/*
++ * yaffs_search_advance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_search_advance(struct yaffs_search_context *sc)
++{
++ if (!sc)
++ return;
++
++ if (sc->next_return == NULL ||
++ list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else {
++ struct list_head *next = sc->next_return->siblings.next;
++
++ if (next == &sc->dir_obj->variant.dir_variant.children)
++ sc->next_return = NULL; /* end of list */
++ else
++ sc->next_return =
++ list_entry(next, struct yaffs_obj, siblings);
++ }
++}
++
++/*
++ * yaffs_remove_obj_callback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
++{
++
++ struct list_head *i;
++ struct yaffs_search_context *sc;
++ struct list_head *search_contexts =
++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
++
++ /* Iterate through the directory search contexts.
++ * If any are currently on the object being removed, then advance
++ * the search context to the next object to prevent a hanging pointer.
++ */
++ list_for_each(i, search_contexts) {
++ sc = list_entry(i, struct yaffs_search_context, others);
++ if (sc->next_return == obj)
++ yaffs_search_advance(sc);
++ }
++
++}
++
++
++/*-----------------------------------------------------------------*/
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++static int yaffs_readdir(struct file *file, struct dir_context *ctx)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = file->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(file->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = ctx->pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)file->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (!dir_emit_dotdot(file, ctx)) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ ctx->pos++;
++ }
++
++ curoffs = 1;
++
++ /* If the directory has changed since the open or last call to
++ readdir, rewind to after the 2 canned entries. */
++ if (file->f_version != inode->i_version) {
++ offset = 2;
++ ctx->pos = offset;
++ file->f_version = inode->i_version;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (!dir_emit(ctx, name, strlen(name),
++ this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ ctx->pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#else
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = f->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = f->f_pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: starting at %d", (int)offset);
++
++ if (offset == 0) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry . ino %d",
++ (int)inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ f->f_pos++;
++ }
++ if (offset == 1) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: entry .. ino %d",
++ (int)f->f_dentry->d_parent->d_inode->i_ino);
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, "..", 2, offset,
++ f->f_dentry->d_parent->d_inode->i_ino,
++ DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ 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;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_readdir: %s inode %d",
++ name, yaffs_get_obj_inode(l));
++
++ yaffs_gross_unlock(dev);
++
++ if (filldir(dirent,
++ name,
++ strlen(name),
++ offset, this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ f->f_pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++#endif
++
++static const struct file_operations yaffs_dir_operations = {
++ .read = generic_read_dir,
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
++ .iterate = yaffs_readdir,
++#else
++ .readdir = yaffs_readdir,
++#endif
++ .fsync = yaffs_sync_object,
++ .llseek = generic_file_llseek,
++};
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj)
++{
++ if (inode && obj) {
++
++ /* Check mode against the variant type and attempt to repair if broken. */
++ u32 mode = obj->yst_mode;
++ switch (obj->variant_type) {
++ 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_flags |= S_NOATIME;
++
++ inode->i_ino = obj->obj_id;
++ inode->i_mode = obj->yst_mode;
++ i_uid_write(inode, obj->yst_uid);
++ i_gid_write(inode, 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_get_obj_length(obj);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++
++ set_nlink(inode, yaffs_get_obj_link_count(obj));
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
++ inode->i_mode, i_uid_read(inode), i_gid_read(inode),
++ 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_inode_to_obj_lv(inode) = obj;
++
++ obj->my_inode = inode;
++
++ } else {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_fill_inode invalid parameters");
++ }
++
++}
++
++
++
++/*
++ * yaffs background thread functions .
++ * yaffs_bg_thread_fn() the thread function
++ * yaffs_bg_start() launches the background thread.
++ * yaffs_bg_stop() cleans up the background thread.
++ *
++ * NB:
++ * The thread should only run after the yaffs is initialised
++ * The thread should be stopped before yaffs is unmounted.
++ * The thread should not do any writing while the fs is in read only.
++ */
++
++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
++{
++ unsigned erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned scattered = 0; /* Free chunks not in an erased block */
++
++ if (erased_chunks < dev->n_free_chunks)
++ scattered = (dev->n_free_chunks - erased_chunks);
++
++ if (!context->bg_running)
++ return 0;
++ else if (scattered < (dev->param.chunks_per_block * 2))
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 2)
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 4)
++ return 1;
++ else
++ return 2;
++}
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++
++void yaffs_background_waker(unsigned long data)
++{
++ wake_up_process((struct task_struct *)data);
++}
++
++static int yaffs_bg_thread_fn(void *data)
++{
++ struct yaffs_dev *dev = (struct yaffs_dev *)data;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned long now = jiffies;
++ unsigned long next_dir_update = now;
++ unsigned long next_gc = now;
++ unsigned long expires;
++ unsigned int urgency;
++
++ int gc_result;
++ struct timer_list timer;
++
++ yaffs_trace(YAFFS_TRACE_BACKGROUND,
++ "yaffs_background starting for dev %p", (void *)dev);
++
++#ifdef YAFFS_COMPILE_FREEZER
++ set_freezable();
++#endif
++ while (context->bg_running) {
++ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
++
++ if (kthread_should_stop())
++ break;
++
++#ifdef YAFFS_COMPILE_FREEZER
++ if (try_to_freeze())
++ continue;
++#endif
++ yaffs_gross_lock(dev);
++
++ now = jiffies;
++
++ if (time_after(now, next_dir_update) && yaffs_bg_enable) {
++ yaffs_update_dirty_dirs(dev);
++ next_dir_update = now + HZ;
++ }
++
++ if (time_after(now, next_gc) && yaffs_bg_enable) {
++ if (!dev->is_checkpointed) {
++ urgency = yaffs_bg_gc_urgency(dev);
++ gc_result = yaffs_bg_gc(dev, urgency);
++ if (urgency > 1)
++ next_gc = now + HZ / 20 + 1;
++ else if (urgency > 0)
++ next_gc = now + HZ / 10 + 1;
++ else
++ next_gc = now + HZ * 2;
++ } else {
++ /*
++ * gc not running so set to next_dir_update
++ * to cut down on wake ups
++ */
++ next_gc = next_dir_update;
++ }
++ }
++ yaffs_gross_unlock(dev);
++#if 1
++ expires = next_dir_update;
++ if (time_before(next_gc, expires))
++ expires = next_gc;
++ if (time_before(expires, now))
++ expires = now + HZ;
++
++ Y_INIT_TIMER(&timer);
++ timer.expires = expires + 1;
++ timer.data = (unsigned long)current;
++ timer.function = yaffs_background_waker;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_timer(&timer);
++ schedule();
++ del_timer_sync(&timer);
++#else
++ msleep(10);
++#endif
++ }
++
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ int retval = 0;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++
++ if (dev->read_only)
++ return -1;
++
++ context->bg_running = 1;
++
++ context->bg_thread = kthread_run(yaffs_bg_thread_fn,
++ (void *)dev, "yaffs-bg-%d",
++ context->mount_id);
++
++ if (IS_ERR(context->bg_thread)) {
++ retval = PTR_ERR(context->bg_thread);
++ context->bg_thread = NULL;
++ context->bg_running = 0;
++ }
++ return retval;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
++
++ ctxt->bg_running = 0;
++
++ if (ctxt->bg_thread) {
++ kthread_stop(ctxt->bg_thread);
++ ctxt->bg_thread = NULL;
++ }
++}
++#else
++static int yaffs_bg_thread_fn(void *data)
++{
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ return 0;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++}
++#endif
++
++
++static void yaffs_flush_inodes(struct super_block *sb)
++{
++ struct inode *iptr;
++ struct yaffs_obj *obj;
++
++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
++ obj = yaffs_inode_to_obj(iptr);
++ if (obj) {
++ yaffs_trace(YAFFS_TRACE_OS,
++ "flushing obj %d",
++ obj->obj_id);
++ yaffs_flush_file(obj, 1, 0);
++ }
++ }
++}
++
++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ if (!dev)
++ return;
++
++ yaffs_flush_inodes(sb);
++ yaffs_update_dirty_dirs(dev);
++ yaffs_flush_whole_cache(dev);
++ if (do_checkpoint)
++ yaffs_checkpoint_save(dev);
++}
++
++static LIST_HEAD(yaffs_context_list);
++struct mutex yaffs_context_lock;
++
++static void yaffs_put_super(struct super_block *sb)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super");
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "Shutting down yaffs background thread");
++ yaffs_bg_stop(dev);
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ "yaffs background thread shut down");
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_super(sb, 1);
++
++ yaffs_deinitialise(dev);
++
++ yaffs_gross_unlock(dev);
++
++ mutex_lock(&yaffs_context_lock);
++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
++ mutex_unlock(&yaffs_context_lock);
++
++ if (yaffs_dev_to_lc(dev)->spare_buffer) {
++ kfree(yaffs_dev_to_lc(dev)->spare_buffer);
++ yaffs_dev_to_lc(dev)->spare_buffer = NULL;
++ }
++
++ kfree(dev);
++
++ yaffs_put_mtd_device(mtd);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
++ "yaffs_put_super done");
++}
++
++
++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
++{
++ return yaffs_gc_control;
++}
++
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++
++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
++ uint32_t generation)
++{
++ return Y_IGET(sb, ino);
++}
++
++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++struct dentry *yaffs2_get_parent(struct dentry *dentry)
++{
++
++ struct super_block *sb = dentry->d_inode->i_sb;
++ struct dentry *parent = ERR_PTR(-ENOENT);
++ struct inode *inode;
++ unsigned long parent_ino;
++ struct yaffs_obj *d_obj;
++ struct yaffs_obj *parent_obj;
++
++ d_obj = yaffs_inode_to_obj(dentry->d_inode);
++
++ if (d_obj) {
++ parent_obj = d_obj->parent;
++ if (parent_obj) {
++ parent_ino = yaffs_get_obj_inode(parent_obj);
++ inode = Y_IGET(sb, parent_ino);
++
++ if (IS_ERR(inode)) {
++ parent = ERR_CAST(inode);
++ } else {
++ parent = d_obtain_alias(inode);
++ if (!IS_ERR(parent)) {
++ parent = ERR_PTR(-ENOMEM);
++ iput(inode);
++ }
++ }
++ }
++ }
++
++ return parent;
++}
++
++/* Just declare a zero structure as a NULL value implies
++ * using the default functions of exportfs.
++ */
++
++static struct export_operations yaffs_export_ops = {
++ .fh_to_dentry = yaffs2_fh_to_dentry,
++ .fh_to_parent = yaffs2_fh_to_parent,
++ .get_parent = yaffs2_get_parent,
++};
++
++#endif
++
++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
++{
++ /* Clear the association between the inode and
++ * the struct yaffs_obj.
++ */
++ obj->my_inode = NULL;
++ yaffs_inode_to_obj_lv(inode) = NULL;
++
++ /* If the object freeing was deferred, then the real
++ * free happens now.
++ * This should fix the inode inconsistency problem.
++ */
++ yaffs_handle_defered_free(obj);
++}
++
++#ifdef YAFFS_HAS_EVICT_INODE
++/* yaffs_evict_inode combines into one operation what was previously done in
++ * yaffs_clear_inode() and yaffs_delete_inode()
++ *
++ */
++static void yaffs_evict_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ int deleteme = 0;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_evict_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (!inode->i_nlink && !is_bad_inode(inode))
++ deleteme = 1;
++ truncate_inode_pages(&inode->i_data, 0);
++ Y_CLEAR_INODE(inode);
++
++ if (deleteme && obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(dev);
++ }
++}
++#else
++
++/* clear is called to tell the fs to release any per-inode data it holds.
++ * The object might still exist on disk and is just being thrown out of the cache
++ * or else the object has actually been deleted and we're being called via
++ * the chain
++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
++ */
++
++static void yaffs_clear_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_clear_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(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)
++{
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++ struct yaffs_dev *dev;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_delete_inode: ino %d, count %d %s",
++ (int)inode->i_ino, atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object");
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ truncate_inode_pages(&inode->i_data, 0);
++#endif
++ clear_inode(inode);
++}
++#endif
++
++
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++ 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)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#endif
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
++
++ yaffs_gross_lock(dev);
++
++ buf->f_type = YAFFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_namelen = 255;
++
++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
++ /* Do this if chunk size is not a power of 2 */
++
++ uint64_t bytes_in_dev;
++ uint64_t bytes_free;
++
++ bytes_in_dev =
++ ((uint64_t)
++ ((dev->param.end_block - dev->param.start_block +
++ 1))) * ((uint64_t) (dev->param.chunks_per_block *
++ dev->data_bytes_per_chunk));
++
++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
++ buf->f_blocks = bytes_in_dev;
++
++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
++ ((uint64_t) (dev->data_bytes_per_chunk));
++
++ do_div(bytes_free, sb->s_blocksize);
++
++ buf->f_bfree = bytes_free;
++
++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
++
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ } else {
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++ }
++
++ buf->f_files = 0;
++ buf->f_ffree = 0;
++ buf->f_bavail = buf->f_bfree;
++
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++
++
++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
++{
++
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
++ int do_checkpoint;
++ int dirty = yaffs_check_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
++ gc_urgent,
++ dirty ? "dirty" : "clean",
++ request_checkpoint ? "checkpoint requested" : "no checkpoint",
++ oneshot_checkpoint ? " one-shot" : "");
++
++ yaffs_gross_lock(dev);
++ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
++ oneshot_checkpoint) && !dev->is_checkpointed;
++
++ if (dirty || do_checkpoint) {
++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
++ yaffs_clear_super_dirty(dev);
++ if (oneshot_checkpoint)
++ yaffs_auto_checkpoint &= ~4;
++ }
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++
++#ifdef YAFFS_HAS_WRITE_SUPER
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ "yaffs_write_super %s",
++ request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++ return 0;
++#endif
++}
++#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
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
++
++ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++ return 0;
++}
++
++
++
++static const struct super_operations yaffs_super_ops = {
++ .statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++ .read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++ .put_inode = yaffs_put_inode,
++#endif
++ .put_super = yaffs_put_super,
++#ifdef YAFFS_HAS_EVICT_INODE
++ .evict_inode = yaffs_evict_inode,
++#else
++ .delete_inode = yaffs_delete_inode,
++ .clear_inode = yaffs_clear_inode,
++#endif
++ .sync_fs = yaffs_sync_fs,
++#ifdef YAFFS_HAS_WRITE_SUPER
++ .write_super = yaffs_write_super,
++#endif
++};
++
++struct yaffs_options {
++ int inband_tags;
++ int skip_checkpoint_read;
++ int skip_checkpoint_write;
++ int no_cache;
++ int tags_ecc_on;
++ int tags_ecc_overridden;
++ int lazy_loading_enabled;
++ int lazy_loading_overridden;
++ int empty_lost_and_found;
++ int empty_lost_and_found_overridden;
++ int disable_summary;
++};
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(struct 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++;
++
++ 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, "tags-ecc-off")) {
++ options->tags_ecc_on = 0;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "tags-ecc-on")) {
++ options->tags_ecc_on = 1;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-off")) {
++ options->lazy_loading_enabled = 0;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-on")) {
++ options->lazy_loading_enabled = 1;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "disable-summary")) {
++ options->disable_summary = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
++ options->empty_lost_and_found = 0;
++ options->empty_lost_and_found_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
++ options->empty_lost_and_found = 1;
++ options->empty_lost_and_found_overridden = 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 dentry *yaffs_make_root(struct inode *inode)
++{
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
++ struct dentry *root = d_alloc_root(inode);
++
++ if (!root)
++ iput(inode);
++
++ return root;
++#else
++ return d_make_root(inode);
++#endif
++}
++
++
++
++
++static struct super_block *yaffs_internal_read_super(int yaffs_version,
++ struct super_block *sb,
++ void *data, int silent)
++{
++ int n_blocks;
++ struct inode *inode = NULL;
++ struct dentry *root;
++ struct yaffs_dev *dev = 0;
++ char devname_buf[BDEVNAME_SIZE + 1];
++ struct mtd_info *mtd;
++ int err;
++ char *data_str = (char *)data;
++ struct yaffs_linux_context *context = NULL;
++ struct yaffs_param *param;
++
++ int read_only = 0;
++ int inband_tags = 0;
++
++ struct yaffs_options options;
++
++ unsigned mount_id;
++ int found;
++ struct yaffs_linux_context *context_iterator;
++ struct list_head *l;
++
++ if (!sb) {
++ printk(KERN_INFO "yaffs: sb is NULL\n");
++ return NULL;
++ }
++
++ sb->s_magic = YAFFS_MAGIC;
++ sb->s_op = &yaffs_super_ops;
++ sb->s_flags |= MS_NOATIME;
++
++ read_only = ((sb->s_flags & MS_RDONLY) != 0);
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++ sb->s_export_op = &yaffs_export_ops;
++#endif
++
++ 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\" %s\n",
++ sb->s_dev,
++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
++
++ 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;
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: Using yaffs%d", yaffs_version);
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
++ MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ yaffs_devname(sb, devname_buf));
++
++ /* Get the device */
++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++ if (IS_ERR(mtd)) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs: MTD device %u either not valid or unavailable",
++ MINOR(sb->s_dev));
++ return NULL;
++ }
++
++ if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
++ yaffs_version = 2;
++ }
++
++ /* Added NCB 26/5/2006 for completeness */
++ if (yaffs_version == 2 && !options.inband_tags
++ && WRITE_SIZE(mtd) == 512) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
++ yaffs_version = 1;
++ }
++
++ if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
++ options.inband_tags)
++ inband_tags = 1;
++
++ if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++ 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 struct yaffs_dev up for mtd
++ */
++
++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++ read_only = 1;
++ printk(KERN_INFO
++ "yaffs: mtd is read only, setting superblock read only\n"
++ );
++ sb->s_flags |= MS_RDONLY;
++ }
++
++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
++
++ if (!dev || !context) {
++ kfree(dev);
++ kfree(context);
++ dev = NULL;
++ context = NULL;
++
++ /* Deep shit could not allocate device structure */
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
++ );
++ return NULL;
++ }
++ memset(dev, 0, sizeof(struct yaffs_dev));
++ param = &(dev->param);
++
++ memset(context, 0, sizeof(struct yaffs_linux_context));
++ dev->os_context = context;
++ INIT_LIST_HEAD(&(context->context_list));
++ context->dev = dev;
++ context->super = sb;
++
++ dev->read_only = read_only;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ sb->s_fs_info = dev;
++#else
++ sb->u.generic_sbp = dev;
++#endif
++
++
++ dev->driver_context = mtd;
++ param->name = mtd->name;
++
++ /* Set up the memory size parameters.... */
++
++
++ param->n_reserved_blocks = 5;
++ param->n_caches = (options.no_cache) ? 0 : 10;
++ param->inband_tags = inband_tags;
++
++ param->enable_xattr = 1;
++ if (options.lazy_loading_overridden)
++ param->disable_lazy_load = !options.lazy_loading_enabled;
++
++ param->defered_dir_update = 1;
++
++ if (options.tags_ecc_overridden)
++ param->no_tags_ecc = !options.tags_ecc_on;
++
++ param->empty_lost_n_found = 1;
++ param->refresh_period = 500;
++ param->disable_summary = options.disable_summary;
++
++
++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
++ param->disable_bad_block_marking = 1;
++#endif
++ if (options.empty_lost_and_found_overridden)
++ param->empty_lost_n_found = options.empty_lost_and_found;
++
++ /* ... and the functions. */
++ if (yaffs_version == 2) {
++ param->is_yaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ param->total_bytes_per_chunk = mtd->writesize;
++ param->chunks_per_block = mtd->erasesize / mtd->writesize;
++#else
++ param->total_bytes_per_chunk = mtd->oobblock;
++ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
++#endif
++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++ } else {
++ param->is_yaffs2 = 0;
++ n_blocks = YCALCBLOCKS(mtd->size,
++ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
++
++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
++ }
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++
++ yaffs_mtd_drv_install(dev);
++
++ param->sb_dirty_fn = yaffs_set_super_dirty;
++ param->gc_control_fn = yaffs_gc_control_callback;
++
++ yaffs_dev_to_lc(dev)->super = sb;
++
++ param->use_nand_ecc = 1;
++
++ param->skip_checkpt_rd = options.skip_checkpoint_read;
++ param->skip_checkpt_wr = options.skip_checkpoint_write;
++
++ mutex_lock(&yaffs_context_lock);
++ /* Get a mount id */
++ found = 0;
++ for (mount_id = 0; !found; mount_id++) {
++ found = 1;
++ list_for_each(l, &yaffs_context_list) {
++ context_iterator =
++ list_entry(l, struct yaffs_linux_context,
++ context_list);
++ if (context_iterator->mount_id == mount_id)
++ found = 0;
++ }
++ }
++ context->mount_id = mount_id;
++
++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
++ &yaffs_context_list);
++ mutex_unlock(&yaffs_context_lock);
++
++ /* Directory search handling... */
++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
++ param->remove_obj_fn = yaffs_remove_obj_callback;
++
++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
++
++ yaffs_gross_lock(dev);
++
++ err = yaffs_guts_initialise(dev);
++
++ yaffs_trace(YAFFS_TRACE_OS,
++ "yaffs_read_super: guts initialised %s",
++ (err == YAFFS_OK) ? "OK" : "FAILED");
++
++ if (err == YAFFS_OK)
++ yaffs_bg_start(dev);
++
++ if (!context->bg_thread)
++ param->defered_dir_update = 0;
++
++ sb->s_maxbytes = yaffs_max_file_size(dev);
++
++ /* Release lock before yaffs_get_inode() */
++ yaffs_gross_unlock(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;
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
++
++ root = yaffs_make_root(inode);
++
++ if (!root)
++ return NULL;
++
++ sb->s_root = root;
++ if(!dev->is_checkpointed)
++ yaffs_set_super_dirty(dev);
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs_read_super: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
++ 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, 39))
++static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs_mount,
++#else
++ .get_sb = yaffs_read_super,
++#endif
++ .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
++
++
++#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, 39))
++static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
++ const char *dev_name, void *data)
++{
++ return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
++}
++#elif (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",
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
++ .mount = yaffs2_mount,
++#else
++ .get_sb = yaffs2_read_super,
++#endif
++ .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
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++static struct proc_dir_entry *my_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
++{
++ struct yaffs_param *param = &dev->param;
++ int bs[10];
++
++ yaffs_count_blocks_by_state(dev,bs);
++
++ buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
++ buf += sprintf(buf, "end_block............ %d\n", param->end_block);
++ buf += sprintf(buf, "total_bytes_per_chunk %d\n",
++ param->total_bytes_per_chunk);
++ buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
++ buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
++ buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
++ buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
++ buf += sprintf(buf, "empty_lost_n_found... %d\n",
++ param->empty_lost_n_found);
++ buf += sprintf(buf, "disable_lazy_load.... %d\n",
++ param->disable_lazy_load);
++ buf += sprintf(buf, "disable_bad_block_mrk %d\n",
++ param->disable_bad_block_marking);
++ buf += sprintf(buf, "refresh_period....... %d\n",
++ param->refresh_period);
++ buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
++ buf += sprintf(buf, "n_reserved_blocks.... %d\n",
++ param->n_reserved_blocks);
++ buf += sprintf(buf, "always_check_erased.. %d\n",
++ param->always_check_erased);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "block count by state\n");
++ buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
++ bs[0], bs[1], bs[2], bs[3], bs[4]);
++ buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
++ bs[5], bs[6], bs[7], bs[8], bs[9]);
++
++ return buf;
++}
++
++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
++{
++ buf += sprintf(buf, "max file size....... %lld\n",
++ (long long) yaffs_max_file_size(dev));
++ buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
++ dev->data_bytes_per_chunk);
++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
++ buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
++ dev->blocks_in_checkpt);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
++ buf += sprintf(buf, "passive_gc_count..... %u\n",
++ dev->passive_gc_count);
++ buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
++ dev->oldest_dirty_gc_count);
++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
++ buf += sprintf(buf, "n_retried_writes..... %u\n",
++ dev->n_retried_writes);
++ buf += sprintf(buf, "n_retired_blocks..... %u\n",
++ dev->n_retired_blocks);
++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
++ buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
++ dev->n_tags_ecc_fixed);
++ buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
++ dev->n_tags_ecc_unfixed);
++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
++ buf += sprintf(buf, "n_unlinked_files..... %u\n",
++ dev->n_unlinked_files);
++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
++ buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
++ buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
++
++ 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 dev_list.
++ * 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,
++ "Multi-version YAFFS built:" __DATE__ " " __TIME__
++ "\n");
++ else if (step == 1)
++ buf += sprintf(buf, "\n");
++ else {
++ step -= 2;
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (n < (step & ~1)) {
++ n += 2;
++ continue;
++ }
++ if ((step & 1) == 0) {
++ buf +=
++ sprintf(buf, "\nDevice %d \"%s\"\n", n,
++ dev->param.name);
++ buf = yaffs_dump_dev_part0(buf, dev);
++ } else {
++ buf = yaffs_dump_dev_part1(buf, dev);
++ }
++
++ break;
++ }
++ mutex_unlock(&yaffs_context_lock);
++ }
++
++ 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},
++ {"background", YAFFS_TRACE_BACKGROUND},
++ {"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},
++ {"lock", YAFFS_TRACE_LOCK},
++ {"mtd", YAFFS_TRACE_MTD},
++ {"nandaccess", YAFFS_TRACE_NANDACCESS},
++ {"os", YAFFS_TRACE_OS},
++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++ {"scan", YAFFS_TRACE_SCAN},
++ {"mount", YAFFS_TRACE_MOUNT},
++ {"tracing", YAFFS_TRACE_TRACING},
++ {"sync", YAFFS_TRACE_SYNC},
++ {"write", YAFFS_TRACE_WRITE},
++ {"verify", YAFFS_TRACE_VERIFY},
++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
++ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
++ {"all", 0xffffffff},
++ {"none", 0},
++ {NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(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_trace_mask;
++
++ 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_trace_mask = rg | YAFFS_TRACE_ALWAYS;
++
++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
++
++ 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(KERN_DEBUG "%c%s\n", flag,
++ mask_flags[i].mask_name);
++ }
++ }
++
++ return count;
++}
++
++/* Debug strings are of the form:
++ * .bnnn print info on block n
++ * .cobjn,chunkn print nand chunk id for objn:chunkn
++ */
++
++static int yaffs_proc_debug_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++
++ char str[100];
++ char *p0;
++ char *p1;
++ long p1_val;
++ long p0_val;
++ char cmd;
++ struct list_head *item;
++
++ memset(str, 0, sizeof(str));
++ memcpy(str, buf, min(count, sizeof(str) -1));
++
++ cmd = str[1];
++
++ p0 = str + 2;
++
++ p1 = p0;
++
++ while (*p1 && *p1 != ',') {
++ p1++;
++ }
++ *p1 = '\0';
++ p1++;
++
++ p0_val = simple_strtol(p0, NULL, 0);
++ p1_val = simple_strtol(p1, NULL, 0);
++
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (cmd == 'b') {
++ struct yaffs_block_info *bi;
++
++ bi = yaffs_get_block_info(dev,p0_val);
++
++ if(bi) {
++ printk("Block %d: state %d, retire %d, use %d, seq %d\n",
++ (int)p0_val, bi->block_state,
++ bi->needs_retiring, bi->pages_in_use,
++ bi->seq_number);
++ }
++ } else if (cmd == 'c') {
++ struct yaffs_obj *obj;
++ int nand_chunk;
++
++ obj = yaffs_find_by_number(dev, p0_val);
++ if (!obj)
++ printk("No obj %d\n", (int)p0_val);
++ else {
++ if(p1_val == 0)
++ nand_chunk = obj->hdr_chunk;
++ else
++ nand_chunk =
++ yaffs_find_chunk_in_file(obj,
++ p1_val, NULL);
++ printk("Nand chunk for %d:%d is %d\n",
++ (int)p0_val, (int)p1_val, nand_chunk);
++ }
++ }
++ }
++
++ mutex_unlock(&yaffs_context_lock);
++
++ return count;
++}
++
++static int yaffs_proc_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ if (buf[0] == '.')
++ return yaffs_proc_debug_write(file, buf, count, data);
++ return yaffs_proc_write_trace_options(file, buf, count, data);
++}
++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */
++
++/* 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[] = {
++ {&yaffs_fs_type, 0},
++ {&yaffs2_fs_type, 0},
++ {NULL, 0}
++};
++
++static int __init init_yaffs_fs(void)
++{
++ int error = 0;
++ struct file_system_to_install *fsinst;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " Installing.");
++
++ mutex_init(&yaffs_context_lock);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ /* Install the proc_fs entries */
++ my_proc_entry = create_proc_entry("yaffs",
++ S_IRUGO | S_IFREG, YPROC_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;
++ }
++#endif
++
++ /* 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;
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "yaffs built " __DATE__ " " __TIME__ " removing.");
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
++ remove_proc_entry("yaffs", YPROC_ROOT);
++#endif
++
++ 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-2011");
++MODULE_LICENSE("GPL");
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.4.90/fs/yaffs2/yaffs_yaffs1.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_yaffs1.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,422 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_yaffs1.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++#include "yaffs_attribs.h"
++
++int yaffs1_scan(struct yaffs_dev *dev)
++{
++ struct yaffs_ext_tags tags;
++ int blk;
++ int result;
++ int chunk;
++ int c;
++ int deleted;
++ enum yaffs_block_state state;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int alloc_failed = 0;
++ struct yaffs_shadow_fixer *shadow_fixers = NULL;
++ u8 *chunk_data;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs1_scan starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, state, seq_number);
++
++ if (state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ }
++ bi++;
++ }
++
++ /* For each block.... */
++ for (blk = dev->internal_start_block;
++ !alloc_failed && blk <= dev->internal_end_block; blk++) {
++
++ cond_resched();
++
++ bi = yaffs_get_block_info(dev, blk);
++ state = bi->block_state;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ for (c = 0;
++ !alloc_failed && c < dev->param.chunks_per_block &&
++ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
++ /* Read the tags and decide what to do */
++ chunk = blk * dev->param.chunks_per_block + c;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
++ tags.is_deleted) {
++ /* YAFFS1 only...
++ * A deleted chunk
++ */
++ deleted++;
++ dev->n_free_chunks++;
++ } else if (!tags.chunk_used) {
++ /* An unassigned chunk in the block
++ * This means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (c == 0) {
++ /* We're looking at the first chunk in
++ *the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ /* this is the block being allocated */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, c);
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = c;
++ dev->alloc_block_finder = blk;
++
++ }
++
++ dev->n_free_chunks +=
++ (dev->param.chunks_per_block - c);
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ unsigned int endpos;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ /* PutChunkIntoFile checks for a clash
++ * (two data chunks with the same chunk_id).
++ */
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in) {
++ if (!yaffs_put_chunk_in_file
++ (in, tags.chunk_id, chunk, 1))
++ alloc_failed = 1;
++ }
++
++ endpos =
++ (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk +
++ tags.n_bytes;
++ if (in &&
++ in->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE &&
++ in->variant.file_variant.scanned_size <
++ endpos) {
++ in->variant.file_variant.scanned_size =
++ endpos;
++ if (!dev->param.use_header_file_size) {
++ in->variant.
++ file_variant.file_size =
++ in->variant.
++ file_variant.scanned_size;
++ }
++
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Make the object
++ */
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ in = yaffs_find_by_number(dev, tags.obj_id);
++ if (in && in->variant_type != oh->type) {
++ /* This should not happen, but somehow
++ * Wev'e ended up with an obj_id that
++ * has been reused but not yet deleted,
++ * and worse still it has changed type.
++ * Delete the old object.
++ */
++
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ oh->type);
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in && oh->shadows_obj > 0) {
++
++ struct yaffs_shadow_fixer *fixer;
++ fixer =
++ kmalloc(sizeof
++ (struct yaffs_shadow_fixer),
++ GFP_NOFS);
++ if (fixer) {
++ fixer->next = shadow_fixers;
++ shadow_fixers = fixer;
++ fixer->obj_id = tags.obj_id;
++ fixer->shadowed_id =
++ oh->shadows_obj;
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Shadow fixer: %d shadows %d",
++ fixer->obj_id,
++ fixer->shadowed_id);
++
++ }
++
++ }
++
++ if (in && in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate and need to
++ * resolve it. */
++
++ unsigned existing_serial = in->serial;
++ unsigned new_serial =
++ tags.serial_number;
++
++ if (((existing_serial + 1) & 3) ==
++ new_serial) {
++ /* Use new one - destroy the
++ * exisiting one */
++ yaffs_chunk_del(dev,
++ in->hdr_chunk,
++ 1, __LINE__);
++ in->valid = 0;
++ } else {
++ /* Use existing - destroy
++ * this one. */
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++ }
++ }
++
++ if (in && !in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ } else if (in && !in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ in->dirty = 0;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (!parent)
++ alloc_failed = 1;
++ if (parent && parent->variant_type ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.
++ children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, a problem....
++ * We're trying to use a
++ * non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (dev->param.
++ use_header_file_size)
++ in->variant.
++ file_variant.file_size
++ = yaffs_oh_to_size(oh);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.
++ hardlink_variant.equiv_id =
++ oh->equiv_id;
++ list_add(&in->hard_links,
++ &hard_list);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.
++ alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.
++ symlink_variant.alias)
++ alloc_failed = 1;
++ break;
++ }
++ }
++ }
++ }
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning,
++ * then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ /* If the block was partially allocated then
++ * treat it as fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ bi->block_state = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ yaffs_block_became_dirty(dev, blk);
++ }
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add
++ * these hardlinks.
++ */
++
++ yaffs_link_fixup(dev, &hard_list);
++
++ /*
++ * Fix up any shadowed objects.
++ * There should not be more than one of these.
++ */
++ {
++ struct yaffs_shadow_fixer *fixer;
++ struct yaffs_obj *obj;
++
++ while (shadow_fixers) {
++ fixer = shadow_fixers;
++ shadow_fixers = fixer->next;
++ /* Complete the rename transaction by deleting the
++ * shadowed object then setting the object header
++ to unshadowed.
++ */
++ obj = yaffs_find_by_number(dev, fixer->shadowed_id);
++ if (obj)
++ yaffs_del_obj(obj);
++
++ obj = yaffs_find_by_number(dev, fixer->obj_id);
++
++ if (obj)
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ kfree(fixer);
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.4.90/fs/yaffs2/yaffs_yaffs1.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_yaffs1.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS1_H__
++#define __YAFFS_YAFFS1_H__
++
++#include "yaffs_guts.h"
++int yaffs1_scan(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.4.90/fs/yaffs2/yaffs_yaffs2.c
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_yaffs2.c 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,1534 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_checkptrw.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_verify.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/*
++ * Checkpoints are really no benefit on very small partitions.
++ *
++ * To save space on small partitions don't bother with checkpoints unless
++ * the partition is at least this big.
++ */
++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
++#define YAFFS_SMALL_HOLE_THRESHOLD 4
++
++/*
++ * Oldest Dirty Sequence Number handling.
++ */
++
++/* yaffs_calc_oldest_dirty_seq()
++ * yaffs2_find_oldest_dirty_seq()
++ * Calculate the oldest dirty sequence number if we don't know it.
++ */
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ int i;
++ unsigned seq;
++ unsigned block_no = 0;
++ struct yaffs_block_info *b;
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ /* Find the oldest dirty sequence number. */
++ seq = dev->seq_number + 1;
++ b = dev->block_info;
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
++ (b->pages_in_use - b->soft_del_pages) <
++ dev->param.chunks_per_block &&
++ b->seq_number < seq) {
++ seq = b->seq_number;
++ block_no = i;
++ }
++ b++;
++ }
++
++ if (block_no) {
++ dev->oldest_dirty_seq = seq;
++ dev->oldest_dirty_block = block_no;
++ }
++}
++
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->oldest_dirty_seq)
++ yaffs_calc_oldest_dirty_seq(dev);
++}
++
++/*
++ * yaffs_clear_oldest_dirty_seq()
++ * Called when a block is erased or marked bad. (ie. when its seq_number
++ * becomes invalid). If the value matches the oldest then we clear
++ * dev->oldest_dirty_seq to force its recomputation.
++ */
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++ }
++}
++
++/*
++ * yaffs2_update_oldest_dirty_seq()
++ * Update the oldest dirty sequence number whenever we dirty a block.
++ * Only do this if the oldest_dirty_seq is actually being tracked.
++ */
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (dev->oldest_dirty_seq) {
++ if (dev->oldest_dirty_seq > bi->seq_number) {
++ dev->oldest_dirty_seq = bi->seq_number;
++ dev->oldest_dirty_block = block_no;
++ }
++ }
++}
++
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return 1; /* disqualification only applies to yaffs2. */
++
++ if (!bi->has_shrink_hdr)
++ return 1; /* can gc */
++
++ yaffs2_find_oldest_dirty_seq(dev);
++
++ /* Can't do gc of this block if there are any blocks older than this
++ * one that have discarded pages.
++ */
++ return (bi->seq_number <= dev->oldest_dirty_seq);
++}
++
++/*
++ * yaffs2_find_refresh_block()
++ * periodically finds the oldest full block by sequence number for refreshing.
++ * Only for yaffs2.
++ */
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
++{
++ u32 b;
++ u32 oldest = 0;
++ u32 oldest_seq = 0;
++ struct yaffs_block_info *bi;
++
++ if (!dev->param.is_yaffs2)
++ return oldest;
++
++ /*
++ * If refresh period < 10 then refreshing is disabled.
++ */
++ if (dev->param.refresh_period < 10)
++ return oldest;
++
++ /*
++ * Fix broken values.
++ */
++ if (dev->refresh_skip > dev->param.refresh_period)
++ dev->refresh_skip = dev->param.refresh_period;
++
++ if (dev->refresh_skip > 0)
++ return oldest;
++
++ /*
++ * Refresh skip is now zero.
++ * We'll do a refresh this time around....
++ * Update the refresh skip and find the oldest block.
++ */
++ dev->refresh_skip = dev->param.refresh_period;
++ dev->refresh_count++;
++ bi = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++
++ if (oldest < 1 || bi->seq_number < oldest_seq) {
++ oldest = b;
++ oldest_seq = bi->seq_number;
++ }
++ }
++ bi++;
++ }
++
++ if (oldest > 0) {
++ yaffs_trace(YAFFS_TRACE_GC,
++ "GC refresh count %d selected block %d with seq_number %d",
++ dev->refresh_count, oldest, oldest_seq);
++ }
++
++ return oldest;
++}
++
++int yaffs2_checkpt_required(struct yaffs_dev *dev)
++{
++ int nblocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ return !dev->param.skip_checkpt_wr &&
++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
++}
++
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
++{
++ int retval;
++ int n_bytes = 0;
++ int n_blocks;
++ int dev_blocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
++ /* Not a valid value so recalculate */
++ dev_blocks = dev->param.end_block - dev->param.start_block + 1;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(struct yaffs_checkpt_dev);
++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
++ n_bytes += dev_blocks * dev->chunk_bit_stride;
++ n_bytes +=
++ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
++ dev->n_obj;
++ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(u32); /* checksum */
++
++ /* Round up and add 2 blocks to allow for some bad blocks,
++ * so add 3 */
++
++ n_blocks =
++ (n_bytes /
++ (dev->data_bytes_per_chunk *
++ dev->param.chunks_per_block)) + 3;
++
++ dev->checkpoint_blocks_required = n_blocks;
++ }
++
++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
++ if (retval < 0)
++ retval = 0;
++ return retval;
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++
++ memset(&cp, 0, sizeof(cp));
++
++ cp.struct_type = sizeof(cp);
++ cp.magic = YAFFS_MAGIC;
++ cp.version = YAFFS_CHECKPOINT_VERSION;
++ cp.head = (head) ? 1 : 0;
++
++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok)
++ ok = (cp.struct_type == sizeof(cp)) &&
++ (cp.magic == YAFFS_MAGIC) &&
++ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++ (cp.head == ((head) ? 1 : 0));
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
++ struct yaffs_dev *dev)
++{
++ cp->n_erased_blocks = dev->n_erased_blocks;
++ cp->alloc_block = dev->alloc_block;
++ cp->alloc_page = dev->alloc_page;
++ cp->n_free_chunks = dev->n_free_chunks;
++
++ cp->n_deleted_files = dev->n_deleted_files;
++ cp->n_unlinked_files = dev->n_unlinked_files;
++ cp->n_bg_deletions = dev->n_bg_deletions;
++ cp->seq_number = dev->seq_number;
++
++}
++
++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
++ struct yaffs_checkpt_dev *cp)
++{
++ dev->n_erased_blocks = cp->n_erased_blocks;
++ dev->alloc_block = cp->alloc_block;
++ dev->alloc_page = cp->alloc_page;
++ dev->n_free_chunks = cp->n_free_chunks;
++
++ dev->n_deleted_files = cp->n_deleted_files;
++ dev->n_unlinked_files = cp->n_unlinked_files;
++ dev->n_bg_deletions = cp->n_bg_deletions;
++ dev->seq_number = cp->seq_number;
++}
++
++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ int ok;
++
++ /* Write device runtime values */
++ yaffs2_dev_to_checkpt_dev(&cp, dev);
++ cp.struct_type = sizeof(cp);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ /* Write block info */
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
++ if (!ok)
++ return 0;
++
++ /* Write chunk bits */
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks =
++ (dev->internal_end_block - dev->internal_start_block + 1);
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ if (cp.struct_type != sizeof(cp))
++ return 0;
++
++ yaffs_checkpt_dev_to_dev(dev, &cp);
++
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++
++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
++
++ if (!ok)
++ return 0;
++
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++
++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
++ struct yaffs_obj *obj)
++{
++ cp->obj_id = obj->obj_id;
++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
++ cp->hdr_chunk = obj->hdr_chunk;
++ cp->variant_type = obj->variant_type;
++ cp->deleted = obj->deleted;
++ cp->soft_del = obj->soft_del;
++ cp->unlinked = obj->unlinked;
++ cp->fake = obj->fake;
++ cp->rename_allowed = obj->rename_allowed;
++ cp->unlink_allowed = obj->unlink_allowed;
++ cp->serial = obj->serial;
++ cp->n_data_chunks = obj->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
++}
++
++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
++ struct yaffs_checkpt_obj *cp)
++{
++ struct yaffs_obj *parent;
++
++ if (obj->variant_type != cp->variant_type) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
++ cp->obj_id, cp->variant_type, cp->hdr_chunk,
++ obj->variant_type);
++ return 0;
++ }
++
++ obj->obj_id = cp->obj_id;
++
++ if (cp->parent_id)
++ parent = yaffs_find_or_create_by_number(obj->my_dev,
++ cp->parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ else
++ parent = NULL;
++
++ if (parent) {
++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_trace(YAFFS_TRACE_ALWAYS,
++ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
++ cp->obj_id, cp->parent_id,
++ cp->variant_type, cp->hdr_chunk,
++ parent->variant_type);
++ return 0;
++ }
++ yaffs_add_obj_to_dir(parent, obj);
++ }
++
++ obj->hdr_chunk = cp->hdr_chunk;
++ obj->variant_type = cp->variant_type;
++ obj->deleted = cp->deleted;
++ obj->soft_del = cp->soft_del;
++ obj->unlinked = cp->unlinked;
++ obj->fake = cp->fake;
++ obj->rename_allowed = cp->rename_allowed;
++ obj->unlink_allowed = cp->unlink_allowed;
++ obj->serial = cp->serial;
++ obj->n_data_chunks = cp->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
++
++ if (obj->hdr_chunk > 0)
++ obj->lazy_loaded = 1;
++ return 1;
++}
++
++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
++ struct yaffs_tnode *tn, u32 level,
++ int chunk_offset)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++ int ok = 1;
++ u32 base_offset;
++
++ if (!tn)
++ return 1;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (!tn->internal[i])
++ continue;
++ ok = yaffs2_checkpt_tnode_worker(in,
++ tn->internal[i],
++ level - 1,
++ (chunk_offset <<
++ YAFFS_TNODES_INTERNAL_BITS) + i);
++ }
++ return ok;
++ }
++
++ /* Level 0 tnode */
++ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
++ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
++ sizeof(base_offset));
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++
++ return ok;
++}
++
++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 end_marker = ~0;
++ int ok = 1;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return ok;
++
++ ok = yaffs2_checkpt_tnode_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.file_variant.
++ top_level, 0);
++ if (ok)
++ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
++ sizeof(end_marker)) == sizeof(end_marker));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 base_chunk;
++ int ok = 1;
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
++ struct yaffs_tnode *tn;
++ int nread = 0;
++
++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
++ sizeof(base_chunk));
++
++ while (ok && (~base_chunk)) {
++ nread++;
++ /* Read level 0 tnode */
++
++ tn = yaffs_get_tnode(dev);
++ if (tn)
++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++ else
++ ok = 0;
++
++ if (tn && ok)
++ ok = yaffs_add_find_tnode_0(dev,
++ file_stuct_ptr,
++ base_chunk, tn) ? 1 : 0;
++
++ if (ok)
++ ok = (yaffs2_checkpt_rd
++ (dev, &base_chunk,
++ sizeof(base_chunk)) == sizeof(base_chunk));
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read tnodes %d records, last %d. ok %d",
++ nread, base_chunk, ok);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int i;
++ int ok = 1;
++ struct list_head *lh;
++
++ /* Iterate through the objects in each hash entry,
++ * dumping them to the checkpointing stream.
++ */
++
++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ obj = list_entry(lh, struct yaffs_obj, hash_link);
++ if (!obj->defered_free) {
++ yaffs2_obj_checkpt_obj(&cp, obj);
++ cp.struct_type = sizeof(cp);
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
++ cp.obj_id, cp.parent_id,
++ cp.variant_type, cp.hdr_chunk, obj);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp,
++ sizeof(cp)) == sizeof(cp));
++
++ if (ok &&
++ obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE)
++ ok = yaffs2_wr_checkpt_tnodes(obj);
++ }
++ }
++ }
++
++ /* Dump end of list */
++ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
++ cp.struct_type = sizeof(cp);
++
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int ok = 1;
++ int done = 0;
++ LIST_HEAD(hard_list);
++
++
++ while (ok && !done) {
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (cp.struct_type != sizeof(cp)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "struct size %d instead of %d ok %d",
++ cp.struct_type, (int)sizeof(cp), ok);
++ ok = 0;
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "Checkpoint read object %d parent %d type %d chunk %d ",
++ cp.obj_id, cp.parent_id, cp.variant_type,
++ cp.hdr_chunk);
++
++ if (ok && cp.obj_id == ~0) {
++ done = 1;
++ } else if (ok) {
++ obj =
++ yaffs_find_or_create_by_number(dev, cp.obj_id,
++ cp.variant_type);
++ if (obj) {
++ ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
++ if (!ok)
++ break;
++ if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs2_rd_checkpt_tnodes(obj);
++ } else if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_HARDLINK) {
++ list_add(&obj->hard_links, &hard_list);
++ }
++ } else {
++ ok = 0;
++ }
++ }
++ }
++
++ if (ok)
++ yaffs_link_fixup(dev, &hard_list);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum);
++
++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
++ sizeof(checkpt_sum));
++
++ if (!ok)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum0;
++ u32 checkpt_sum1;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
++
++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
++ sizeof(checkpt_sum1));
++
++ if (!ok)
++ return 0;
++
++ if (checkpt_sum0 != checkpt_sum1)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!yaffs2_checkpt_required(dev)) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint write");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 1);
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint device");
++ ok = yaffs2_wr_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint objects");
++ ok = yaffs2_wr_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "write checkpoint validity");
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok)
++ ok = yaffs2_wr_checkpt_sum(dev);
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return dev->is_checkpointed;
++}
++
++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!dev->param.is_yaffs2)
++ ok = 0;
++
++ if (ok && dev->param.skip_checkpt_rd) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "skipping checkpoint read");
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */
++
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint device");
++ ok = yaffs2_rd_checkpt_dev(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint objects");
++ ok = yaffs2_rd_checkpt_objs(dev);
++ }
++ if (ok) {
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint validity");
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok) {
++ ok = yaffs2_rd_checkpt_sum(dev);
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "read checkpoint checksum %d", ok);
++ }
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return ok ? 1 : 0;
++}
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
++{
++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
++ dev->is_checkpointed = 0;
++ yaffs2_checkpt_invalidate_stream(dev);
++ }
++ if (dev->param.sb_dirty_fn)
++ dev->param.sb_dirty_fn(dev);
++}
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev)
++{
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "save entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++
++ if (!dev->is_checkpointed) {
++ yaffs2_checkpt_invalidate(dev);
++ yaffs2_wr_checkpt_data(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++ "save exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return dev->is_checkpointed;
++}
++
++int yaffs2_checkpt_restore(struct yaffs_dev *dev)
++{
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore entry: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ retval = yaffs2_rd_checkpt_data(dev);
++
++ if (dev->is_checkpointed) {
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++ }
++
++ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++ "restore exit: is_checkpointed %d",
++ dev->is_checkpointed);
++
++ return retval;
++}
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
++{
++ /* if new_size > old_file_size.
++ * We're going to be writing a hole.
++ * If the hole is small then write zeros otherwise write a start
++ * of hole marker.
++ */
++ loff_t old_file_size;
++ loff_t increase;
++ int small_hole;
++ int result = YAFFS_OK;
++ struct yaffs_dev *dev = NULL;
++ u8 *local_buffer = NULL;
++ int small_increase_ok = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ dev = obj->my_dev;
++
++ /* Bail out if not yaffs2 mode */
++ if (!dev->param.is_yaffs2)
++ return YAFFS_OK;
++
++ old_file_size = obj->variant.file_variant.file_size;
++
++ if (new_size <= old_file_size)
++ return YAFFS_OK;
++
++ increase = new_size - old_file_size;
++
++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
++ small_hole = 1;
++ else
++ small_hole = 0;
++
++ if (small_hole)
++ local_buffer = yaffs_get_temp_buffer(dev);
++
++ if (local_buffer) {
++ /* fill hole with zero bytes */
++ loff_t pos = old_file_size;
++ int this_write;
++ int written;
++ memset(local_buffer, 0, dev->data_bytes_per_chunk);
++ small_increase_ok = 1;
++
++ while (increase > 0 && small_increase_ok) {
++ this_write = increase;
++ if (this_write > dev->data_bytes_per_chunk)
++ this_write = dev->data_bytes_per_chunk;
++ written =
++ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
++ 0);
++ if (written == this_write) {
++ pos += this_write;
++ increase -= this_write;
++ } else {
++ small_increase_ok = 0;
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, local_buffer);
++
++ /* If out of space then reverse any chunks we've added */
++ if (!small_increase_ok)
++ yaffs_resize_file_down(obj, old_file_size);
++ }
++
++ if (!small_increase_ok &&
++ obj->parent &&
++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
++ /* Write a hole start header with the old file size */
++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
++ }
++
++ return result;
++}
++
++struct yaffs_block_index {
++ int seq;
++ int block;
++};
++
++static int yaffs2_ybicmp(const void *a, const void *b)
++{
++ int aseq = ((struct yaffs_block_index *)a)->seq;
++ int bseq = ((struct yaffs_block_index *)b)->seq;
++ int ablock = ((struct yaffs_block_index *)a)->block;
++ int bblock = ((struct yaffs_block_index *)b)->block;
++
++ if (aseq == bseq)
++ return ablock - bblock;
++
++ return aseq - bseq;
++}
++
++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi,
++ int blk, int chunk_in_block,
++ int *found_chunks,
++ u8 *chunk_data,
++ struct list_head *hard_list,
++ int summary_available)
++{
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int equiv_id;
++ loff_t file_size;
++ int is_shrink;
++ int is_unlinked;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++ int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
++ struct yaffs_file_var *file_var;
++ struct yaffs_hardlink_var *hl_var;
++ struct yaffs_symlink_var *sl_var;
++
++ if (summary_available) {
++ result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
++ tags.seq_number = bi->seq_number;
++ }
++
++ if (!summary_available || tags.obj_id == 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
++ dev->tags_used++;
++ } else {
++ dev->summary_used++;
++ }
++
++ /* Let's have a good look at this chunk... */
++
++ if (!tags.chunk_used) {
++ /* An unassigned chunk in the block.
++ * If there are used chunks after this one, then
++ * it is a chunk that was skipped due to failing
++ * the erased check. Just skip it so that it can
++ * be deleted.
++ * But, more typically, We get here when this is
++ * an unallocated chunk and his means that
++ * either the block is empty or this is the one
++ * being allocated from
++ */
++
++ if (*found_chunks) {
++ /* This is a chunk that was skipped due
++ * to failing the erased check */
++ } else if (chunk_in_block == 0) {
++ /* We're looking at the first chunk in
++ * the block so the block is unused */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ if (dev->seq_number == bi->seq_number) {
++ /* Allocating from this block*/
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Allocating from %d %d",
++ blk, chunk_in_block);
++
++ bi->block_state =
++ YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = chunk_in_block;
++ dev->alloc_block_finder = blk;
++ } else {
++ /* This is a partially written block
++ * that is not the current
++ * allocation block.
++ */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Partially written block %d detected. gc will fix this.",
++ blk);
++ }
++ }
++ }
++
++ dev->n_free_chunks++;
++
++ } else if (tags.ecc_result ==
++ YAFFS_ECC_RESULT_UNFIXED) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ " Unfixed ECC in chunk(%d:%d), chunk ignored",
++ blk, chunk_in_block);
++ dev->n_free_chunks++;
++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
++ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
++ tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
++ (tags.chunk_id > 0 &&
++ tags.n_bytes > dev->data_bytes_per_chunk) ||
++ tags.seq_number != bi->seq_number) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
++ blk, chunk_in_block, tags.obj_id,
++ tags.chunk_id, tags.n_bytes);
++ dev->n_free_chunks++;
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ loff_t endpos;
++ loff_t chunk_base = (tags.chunk_id - 1) *
++ dev->data_bytes_per_chunk;
++
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!in)
++ /* Out of memory */
++ alloc_failed = 1;
++
++ if (in &&
++ in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
++ chunk_base < in->variant.file_variant.shrink_size) {
++ /* This has not been invalidated by
++ * a resize */
++ if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
++ chunk, -1))
++ alloc_failed = 1;
++
++ /* File size is calculated by looking at
++ * the data chunks if we have not
++ * seen an object header yet.
++ * Stop this practice once we find an
++ * object header.
++ */
++ endpos = chunk_base + tags.n_bytes;
++
++ if (!in->valid &&
++ in->variant.file_variant.scanned_size < endpos) {
++ in->variant.file_variant.
++ scanned_size = endpos;
++ in->variant.file_variant.
++ file_size = endpos;
++ }
++ } else if (in) {
++ /* This chunk has been invalidated by a
++ * resize, or a past file deletion
++ * so delete the chunk*/
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make
++ * the object
++ */
++ *found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
++ bi->pages_in_use++;
++
++ oh = NULL;
++ in = NULL;
++
++ if (tags.extra_available) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ tags.extra_obj_type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ if (!in ||
++ (!in->valid && dev->param.disable_lazy_load) ||
++ tags.extra_shadows ||
++ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
++
++ /* If we don't have valid info then we
++ * need to read the chunk
++ * TODO In future we can probably defer
++ * reading the chunk and living with
++ * invalid data until needed.
++ */
++
++ result = yaffs_rd_chunk_tags_nand(dev,
++ chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ if (dev->param.inband_tags) {
++ /* Fix up the header if they got
++ * corrupted by inband tags */
++ oh->shadows_obj =
++ oh->inband_shadowed_obj_id;
++ oh->is_shrink =
++ oh->inband_is_shrink;
++ }
++
++ if (!in) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id, oh->type);
++ if (!in)
++ alloc_failed = 1;
++ }
++ }
++
++ if (!in) {
++ /* TODO Hoosterman we have a problem! */
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
++ tags.obj_id, chunk);
++ return YAFFS_FAIL;
++ }
++
++ if (in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate that will be
++ * discarded, but we first have to suck
++ * out resize info if it is a file.
++ */
++ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
++ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
++ (tags.extra_available &&
++ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ )) {
++ loff_t this_size = (oh) ?
++ yaffs_oh_to_size(oh) :
++ tags.extra_file_size;
++ u32 parent_obj_id = (oh) ?
++ oh->parent_obj_id :
++ tags.extra_parent_id;
++
++ is_shrink = (oh) ?
++ oh->is_shrink :
++ tags.extra_is_shrink;
++
++ /* If it is deleted (unlinked
++ * at start also means deleted)
++ * we treat the file size as
++ * being zeroed at this point.
++ */
++ if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
++ parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
++ this_size = 0;
++ is_shrink = 1;
++ }
++
++ if (is_shrink &&
++ in->variant.file_variant.shrink_size >
++ this_size)
++ in->variant.file_variant.shrink_size =
++ this_size;
++
++ if (is_shrink)
++ bi->has_shrink_hdr = 1;
++ }
++ /* Use existing - destroy this one. */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ }
++
++ if (!in->valid && in->variant_type !=
++ (oh ? oh->type : tags.extra_obj_type)) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
++ oh ? oh->type : tags.extra_obj_type,
++ in->variant_type, tags.obj_id,
++ chunk);
++ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
++ }
++
++ if (!in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle
++ * with directory structure */
++ in->valid = 1;
++
++ if (oh) {
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->lazy_loaded = 0;
++ } else {
++ in->lazy_loaded = 1;
++ }
++ in->hdr_chunk = chunk;
++
++ } else if (!in->valid) {
++ /* we need to load this info */
++ in->valid = 1;
++ in->hdr_chunk = chunk;
++ if (oh) {
++ in->variant_type = oh->type;
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++
++ if (oh->shadows_obj > 0)
++ yaffs_handle_shadowed_obj(dev,
++ oh->shadows_obj, 1);
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ parent = yaffs_find_or_create_by_number(dev,
++ oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = yaffs_oh_to_size(oh);
++ is_shrink = oh->is_shrink;
++ equiv_id = oh->equiv_id;
++ } else {
++ in->variant_type = tags.extra_obj_type;
++ parent = yaffs_find_or_create_by_number(dev,
++ tags.extra_parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = tags.extra_file_size;
++ is_shrink = tags.extra_is_shrink;
++ equiv_id = tags.extra_equiv_id;
++ in->lazy_loaded = 1;
++ }
++ in->dirty = 0;
++
++ if (!parent)
++ alloc_failed = 1;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ if (parent &&
++ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.children);
++ } else if (!parent ||
++ parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * Trying to use a non-directory as a directory
++ */
++
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ );
++ parent = dev->lost_n_found;
++ }
++ yaffs_add_obj_to_dir(parent, in);
++
++ is_unlinked = (parent == dev->del_dir) ||
++ (parent == dev->unlinked_dir);
++
++ if (is_shrink)
++ /* Mark the block */
++ bi->has_shrink_hdr = 1;
++
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent
++ * object is scanned we put them all in a list.
++ * After scanning is complete, we should have all the
++ * objects, so we run through this list and fix up all
++ * the chains.
++ */
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ file_var = &in->variant.file_variant;
++ if (file_var->scanned_size < file_size) {
++ /* This covers the case where the file
++ * size is greater than the data held.
++ * This will happen if the file is
++ * resized to be larger than its
++ * current data extents.
++ */
++ file_var->file_size = file_size;
++ file_var->scanned_size = file_size;
++ }
++
++ if (file_var->shrink_size > file_size)
++ file_var->shrink_size = file_size;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ hl_var = &in->variant.hardlink_variant;
++ if (!is_unlinked) {
++ hl_var->equiv_id = equiv_id;
++ list_add(&in->hard_links, hard_list);
++ }
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ sl_var = &in->variant.symlink_variant;
++ if (oh) {
++ sl_var->alias =
++ yaffs_clone_str(oh->alias);
++ if (!sl_var->alias)
++ alloc_failed = 1;
++ }
++ break;
++ }
++ }
++ }
++ return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
++}
++
++int yaffs2_scan_backwards(struct yaffs_dev *dev)
++{
++ int blk;
++ int block_iter;
++ int start_iter;
++ int end_iter;
++ int n_to_scan = 0;
++ enum yaffs_block_state state;
++ int c;
++ int deleted;
++ LIST_HEAD(hard_list);
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ u8 *chunk_data;
++ int found_chunks;
++ int alloc_failed = 0;
++ struct yaffs_block_index *block_index = NULL;
++ int alt_block_index = 0;
++ int summary_available;
++
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
++ dev->internal_start_block, dev->internal_end_block);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ block_index =
++ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
++
++ if (!block_index) {
++ block_index =
++ vmalloc(n_blocks * sizeof(struct yaffs_block_index));
++ alt_block_index = 1;
++ }
++
++ if (!block_index) {
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "yaffs2_scan_backwards() could not allocate block index!"
++ );
++ return YAFFS_FAIL;
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ chunk_data = yaffs_get_temp_buffer(dev);
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
++ "Block scanning block %d state %d seq %d",
++ blk, bi->block_state, seq_number);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ dev->blocks_in_checkpt++;
++
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is bad", blk);
++ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ } else if (bi->block_state ==
++ YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* Determine the highest sequence number */
++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++ block_index[n_to_scan].seq = seq_number;
++ block_index[n_to_scan].block = blk;
++ n_to_scan++;
++ if (seq_number >= dev->seq_number)
++ dev->seq_number = seq_number;
++ } else {
++ /* TODO: Nasty sequence number! */
++ yaffs_trace(YAFFS_TRACE_SCAN,
++ "Block scanning block %d has bad sequence number %d",
++ blk, seq_number);
++ }
++ }
++ bi++;
++ }
++
++ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
++
++ cond_resched();
++
++ /* Sort the blocks by sequence number */
++ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
++ yaffs2_ybicmp, NULL);
++
++ cond_resched();
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "...done");
++
++ /* Now scan the blocks looking at the data. */
++ start_iter = 0;
++ end_iter = n_to_scan - 1;
++ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
++
++ /* For each block.... backwards */
++ for (block_iter = end_iter;
++ !alloc_failed && block_iter >= start_iter;
++ block_iter--) {
++ /* Cooperative multitasking! This loop can run for so
++ long that watchdog timers expire. */
++ cond_resched();
++
++ /* get the block to scan in the correct order */
++ blk = block_index[block_iter].block;
++ bi = yaffs_get_block_info(dev, blk);
++ deleted = 0;
++
++ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
++
++ /* For each chunk in each block that needs scanning.... */
++ found_chunks = 0;
++ if (summary_available)
++ c = dev->chunks_per_summary - 1;
++ else
++ c = dev->param.chunks_per_block - 1;
++
++ for (/* c is already initialised */;
++ !alloc_failed && c >= 0 &&
++ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
++ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
++ c--) {
++ /* Scan backwards...
++ * Read the tags and decide what to do
++ */
++ if (yaffs2_scan_chunk(dev, bi, blk, c,
++ &found_chunks, chunk_data,
++ &hard_list, summary_available) ==
++ YAFFS_FAIL)
++ alloc_failed = 1;
++ }
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
++ /* If we got this far while scanning, then the block
++ * is fully allocated. */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_block_became_dirty(dev, blk);
++ }
++ }
++
++ yaffs_skip_rest_of_block(dev);
++
++ if (alt_block_index)
++ vfree(block_index);
++ else
++ kfree(block_index);
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++ yaffs_link_fixup(dev, &hard_list);
++
++ yaffs_release_temp_buffer(dev, chunk_data);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
++
++ return YAFFS_OK;
++}
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.4.90/fs/yaffs2/yaffs_yaffs2.h
+--- linux-3.4.90.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yaffs_yaffs2.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS2_H__
++#define __YAFFS_YAFFS2_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi);
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
++int yaffs2_checkpt_required(struct yaffs_dev *dev);
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
++int yaffs2_checkpt_save(struct yaffs_dev *dev);
++int yaffs2_checkpt_restore(struct yaffs_dev *dev);
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
++int yaffs2_scan_backwards(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.4.90.orig/fs/yaffs2/yportenv.h linux-3.4.90/fs/yaffs2/yportenv.h
+--- linux-3.4.90.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-3.4.90/fs/yaffs2/yportenv.h 2014-05-17 15:08:09.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#ifdef YAFFS_OUT_OF_TREE
++#include "moduleconfig.h"
++#endif
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/xattr.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/sort.h>
++#include <linux/bitops.h>
++
++/* These type wrappings are used to support Unicode names in WinCE. */
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#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 compile_time_assertion(assertion) \
++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++
++#define yaffs_printf(msk, fmt, ...) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
++
++#define yaffs_trace(msk, fmt, ...) do { \
++ if (yaffs_trace_mask & (msk)) \
++ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
++} while (0)
++
++
++#endif
diff --git a/target/linux/patches/3.12.18/zlib-inflate.patch b/target/linux/patches/3.4.90/zlib-inflate.patch
index 58e1f6d21..58e1f6d21 100644
--- a/target/linux/patches/3.12.18/zlib-inflate.patch
+++ b/target/linux/patches/3.4.90/zlib-inflate.patch