aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/susb/dwc_common_port
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/susb/dwc_common_port')
-rw-r--r--drivers/usb/susb/dwc_common_port/Makefile22
-rw-r--r--drivers/usb/susb/dwc_common_port/Makefile.fbsd17
-rw-r--r--drivers/usb/susb/dwc_common_port/Makefile.linux49
-rw-r--r--drivers/usb/susb/dwc_common_port/changes.txt174
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_cc.c530
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_cc.h228
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_common_fbsd.c1310
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_common_linux.c1420
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_common_nbsd.c1275
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_crypto.c308
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_crypto.h111
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_dh.c301
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_dh.h106
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_list.h594
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_mem.c244
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_modpow.c669
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_modpow.h34
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_notifier.c319
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_notifier.h122
-rw-r--r--drivers/usb/susb/dwc_common_port/dwc_os.h1237
-rw-r--r--drivers/usb/susb/dwc_common_port/usb.h920
21 files changed, 9990 insertions, 0 deletions
diff --git a/drivers/usb/susb/dwc_common_port/Makefile b/drivers/usb/susb/dwc_common_port/Makefile
new file mode 100644
index 00000000000..866e6144ce3
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for DWC_common library
+#
+
+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-y := dwc_common_port_lib.o
+dwc_common_port_lib-y := dwc_cc.o dwc_modpow.o dwc_dh.o \
+ dwc_crypto.o dwc_notifier.o \
+ dwc_common_linux.o dwc_mem.o
+
+clean:
+ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
diff --git a/drivers/usb/susb/dwc_common_port/Makefile.fbsd b/drivers/usb/susb/dwc_common_port/Makefile.fbsd
new file mode 100644
index 00000000000..45db9915b9d
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/Makefile.fbsd
@@ -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 --git a/drivers/usb/susb/dwc_common_port/Makefile.linux b/drivers/usb/susb/dwc_common_port/Makefile.linux
new file mode 100644
index 00000000000..961df3f9c00
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/Makefile.linux
@@ -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 --git a/drivers/usb/susb/dwc_common_port/changes.txt b/drivers/usb/susb/dwc_common_port/changes.txt
new file mode 100644
index 00000000000..f6839f92c27
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/changes.txt
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_cc.c b/drivers/usb/susb/dwc_common_port/dwc_cc.c
new file mode 100644
index 00000000000..36f87683448
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_cc.c
@@ -0,0 +1,530 @@
+/* =========================================================================
+ * $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_DEBUG("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
+ cc = cc_find(cc_if, uid);
+ if (!cc)
+ return 0;
+ } else {
+ cc = alloc_cc(mem_ctx, name, length);
+ if (!cc)
+ return 0;
+ 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_DEBUG("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_DEBUG("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_DEBUG("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_DEBUG("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_DEBUG("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 --git a/drivers/usb/susb/dwc_common_port/dwc_cc.h b/drivers/usb/susb/dwc_common_port/dwc_cc.h
new file mode 100644
index 00000000000..3ed868d761f
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_cc.h
@@ -0,0 +1,228 @@
+/* =========================================================================
+ * $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 --git a/drivers/usb/susb/dwc_common_port/dwc_common_fbsd.c b/drivers/usb/susb/dwc_common_port/dwc_common_fbsd.c
new file mode 100644
index 00000000000..4f28a611f8d
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_common_fbsd.c
@@ -0,0 +1,1310 @@
+#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");
+ WARN_ON(1);
+ 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");
+ WARN_ON(1);
+ 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 --git a/drivers/usb/susb/dwc_common_port/dwc_common_linux.c b/drivers/usb/susb/dwc_common_port/dwc_common_linux.c
new file mode 100644
index 00000000000..b6b4849199d
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_common_linux.c
@@ -0,0 +1,1420 @@
+#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);
+ void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA);
+#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");
+ WARN_ON(1);
+ 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");
+ WARN_ON(1);
+ 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)
+{
+ writel((readl(reg) & ~clear_mask) | set_mask, reg);
+}
+
+#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_DEBUG("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_DEBUG("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_DEBUG("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);
+}
+
+
+/* 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_DEBUG("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_DEBUG("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_DEBUG("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 --git a/drivers/usb/susb/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/susb/dwc_common_port/dwc_common_nbsd.c
new file mode 100644
index 00000000000..49b07e17226
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_common_nbsd.c
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_crypto.c b/drivers/usb/susb/dwc_common_port/dwc_crypto.c
new file mode 100644
index 00000000000..3b035329614
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_crypto.c
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_crypto.h b/drivers/usb/susb/dwc_common_port/dwc_crypto.h
new file mode 100644
index 00000000000..26fcddcfe9b
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_crypto.h
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_dh.c b/drivers/usb/susb/dwc_common_port/dwc_dh.c
new file mode 100644
index 00000000000..5e9a548efcb
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_dh.c
@@ -0,0 +1,301 @@
+/* =========================================================================
+ * $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);
+
+ if (!bignum_num || !bignum_exp || !bignum_mod) {
+ if (bignum_num)
+ dwc_free(mem_ctx, bignum_num);
+ if (bignum_exp)
+ dwc_free(mem_ctx, bignum_exp);
+ if (bignum_mod)
+ dwc_free(mem_ctx, bignum_mod);
+ return -1;
+ }
+
+ 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 --git a/drivers/usb/susb/dwc_common_port/dwc_dh.h b/drivers/usb/susb/dwc_common_port/dwc_dh.h
new file mode 100644
index 00000000000..25c1cc0d588
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_dh.h
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_list.h b/drivers/usb/susb/dwc_common_port/dwc_list.h
new file mode 100644
index 00000000000..89cc325045f
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_list.h
@@ -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) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define DWC_TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = 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 --git a/drivers/usb/susb/dwc_common_port/dwc_mem.c b/drivers/usb/susb/dwc_common_port/dwc_mem.c
new file mode 100644
index 00000000000..afdd9d73bfa
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_mem.c
@@ -0,0 +1,244 @@
+/* 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 current;
+ 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->current += size;
+
+ if (manager->max < manager->current) {
+ manager->max = manager->current;
+ }
+
+ 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->current -= 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->current = 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->current);
+ 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 --git a/drivers/usb/susb/dwc_common_port/dwc_modpow.c b/drivers/usb/susb/dwc_common_port/dwc_modpow.c
new file mode 100644
index 00000000000..3ef50a93671
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_modpow.c
@@ -0,0 +1,669 @@
+/* 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
+#if 0 ////debug by john
+#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
+
+#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 */
+
+ if (!b)
+ return NULL;
+
+ 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);
+ do {
+ BignumDblInt n = (((BignumDblInt)h) << BIGNUM_INT_BITS) | tmplo;
+ q = 0;
+ r = 0;
+ if(n<m0)
+ {
+ q = 0;
+ r = m0;
+ }
+ else
+ {
+ while (n >= m0)
+ {
+ n = n-m0;
+ q++;
+ r = n;
+ }
+ }
+ } while (0);
+
+
+ /* 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)
+ return 0;
+
+ 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)
+ return 0;
+ 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)
+ return 0;
+ b = snewn(mem_ctx, 2 * mlen, BignumInt);
+ if (!b)
+ return 0;
+ 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]);
+
+ if (!result)
+ return result;
+
+ 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 --git a/drivers/usb/susb/dwc_common_port/dwc_modpow.h b/drivers/usb/susb/dwc_common_port/dwc_modpow.h
new file mode 100644
index 00000000000..64f00c276e7
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_modpow.h
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_notifier.c b/drivers/usb/susb/dwc_common_port/dwc_notifier.c
new file mode 100644
index 00000000000..d3dadce4bc7
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_notifier.c
@@ -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_DEBUG(" %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_DEBUG("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 --git a/drivers/usb/susb/dwc_common_port/dwc_notifier.h b/drivers/usb/susb/dwc_common_port/dwc_notifier.h
new file mode 100644
index 00000000000..4a8cdfe565b
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_notifier.h
@@ -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 --git a/drivers/usb/susb/dwc_common_port/dwc_os.h b/drivers/usb/susb/dwc_common_port/dwc_os.h
new file mode 100644
index 00000000000..fa9d5c625a3
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/dwc_os.h
@@ -0,0 +1,1237 @@
+/* =========================================================================
+ * $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
+
+#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(...)
+#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 an informative message.
+ */
+#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
+ dwc_irq(), ## _args)
+#define dwc_info DWC_INFO
+/**
+ * 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
+
+#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
+
+
+/** @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 --git a/drivers/usb/susb/dwc_common_port/usb.h b/drivers/usb/susb/dwc_common_port/usb.h
new file mode 100644
index 00000000000..e408bed2cbe
--- /dev/null
+++ b/drivers/usb/susb/dwc_common_port/usb.h
@@ -0,0 +1,920 @@
+/*
+ * 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 UDESC_BOS 0x0f
+#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_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)
+
+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;
+
+/* 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
+
+/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
+typedef struct wusb_hndshk_data {
+ uint8_t bMessageNumber;
+ uint8_t bStatus;
+ uint8_t tTKID[3];
+ uint8_t bReserved;
+ uint8_t CDID[16];
+ uint8_t Nonce[16];
+ uint8_t MIC[8];
+} UPACKED wusb_hndshk_data_t;
+#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
+
+/* WUSB Connection Context */
+typedef struct wusb_conn_context {
+ uint8_t CHID [16];
+ uint8_t CDID [16];
+ uint8_t CK [16];
+} UPACKED wusb_conn_context_t;
+
+/* WUSB Security Descriptor */
+typedef struct wusb_security_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength;
+ uint8_t bNumEncryptionTypes;
+} UPACKED wusb_security_desc_t;
+
+/* WUSB Encryption Type Descriptor */
+typedef struct wusb_encrypt_type_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint8_t bEncryptionType;
+#define WUETD_UNSECURE 0
+#define WUETD_WIRED 1
+#define WUETD_CCM_1 2
+#define WUETD_RSA_1 3
+
+ uint8_t bEncryptionValue;
+ uint8_t bAuthKeyIndex;
+} UPACKED wusb_encrypt_type_desc_t;
+
+/* WUSB Key Descriptor */
+typedef struct wusb_key_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t tTKID[3];
+ uint8_t bReserved;
+ uint8_t 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;
+
+/* Device Capability Type Codes */
+#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
+
+/* Device Capability Descriptor */
+typedef struct wusb_dev_cap_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+ uint8_t caps[1]; /* Variable length */
+} UPACKED wusb_dev_cap_desc_t;
+
+/* Device Capability Descriptor */
+typedef struct wusb_dev_cap_uwb_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDevCapabilityType;
+ uint8_t bmAttributes;
+ uint16_t wPHYRates; /* Bitmap */
+ uint8_t bmTFITXPowerInfo;
+ uint8_t bmFFITXPowerInfo;
+ uint16_t bmBandGroup;
+ uint8_t bReserved;
+} UPACKED wusb_dev_cap_uwb_desc_t;
+
+/* Wireless USB Endpoint Companion Descriptor */
+typedef struct wusb_endpoint_companion_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bMaxBurst;
+ uint8_t bMaxSequence;
+ uint16_t wMaxStreamDelay;
+ uint16_t wOverTheAirPacketSize;
+ uint8_t bOverTheAirInterval;
+ uint8_t bmCompAttributes;
+} UPACKED wusb_endpoint_companion_desc_t;
+
+/* Wireless USB Numeric Association M1 Data Structure */
+typedef struct wusb_m1_data {
+ uint8_t version;
+ uint16_t langId;
+ uint8_t deviceFriendlyNameLength;
+ uint8_t sha_256_m3[32];
+ uint8_t deviceFriendlyName[256];
+} UPACKED wusb_m1_data_t;
+
+typedef struct wusb_m2_data {
+ uint8_t version;
+ uint16_t langId;
+ uint8_t hostFriendlyNameLength;
+ uint8_t pkh[384];
+ uint8_t hostFriendlyName[256];
+} UPACKED wusb_m2_data_t;
+
+typedef struct wusb_m3_data {
+ uint8_t pkd[384];
+ uint8_t nd;
+} UPACKED wusb_m3_data_t;
+
+typedef struct wusb_m4_data {
+ uint32_t _attributeTypeIdAndLength_1;
+ uint16_t associationTypeId;
+
+ uint32_t _attributeTypeIdAndLength_2;
+ uint16_t associationSubTypeId;
+
+ uint32_t _attributeTypeIdAndLength_3;
+ uint32_t length;
+
+ uint32_t _attributeTypeIdAndLength_4;
+ uint32_t associationStatus;
+
+ uint32_t _attributeTypeIdAndLength_5;
+ uint8_t chid[16];
+
+ uint32_t _attributeTypeIdAndLength_6;
+ uint8_t cdid[16];
+
+ uint32_t _attributeTypeIdAndLength_7;
+ uint8_t bandGroups[2];
+} UPACKED wusb_m4_data_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _USB_H_ */